Code Contracts - Úvod
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu
Reklama
Reklama

Code Contracts - ÚvodCode Contracts - Úvod

 

Code Contracts - Úvod

Google       Google       21. 2. 2011       19 779×

V úvodním článku krátkého seriálu o technologii Code Contracts, která vznikla v Microsoft Research, si ukážeme, v čem nám mohou kontrakty pomoci a jak je používat.

Reklama
Reklama

Pojem kontrakt se běžně používá i mimo svět programování. Pro jistotu uveďme, že kontrakt je dohoda dvou a více stran o vzájemných povinnostech. Jak si tedy představit takový kontrakt v kontextu programování? Například u následující metody třídy String

public string Substring(int startIndex)
parametr startIndex představuje index v zadaném řetězci. Formálně je typu Int32, takže i hodnota -42 sice projede kompilací, ale za běhu dostaneme výjimku. V tomto případě záporná hodnota neodpovídá kontraktu metody Substring, který říká, že bychom jí měli předat index do daného řetězce - nezáporné číslo menší než jeho délka, a tento fakt bychom se dozvěděli například z dokumentace.

Dokumentace je sice hezká věc, ale ještě lepší by byla nějaká systematičtější metoda pro uvádění kontraktu. Možnost zapsat kontrakty tak, aby je mohl zpracovat nějaký automatizovaný nástroj, který by nás mohl upozornit na porušení kontraktu už při kompilaci. Přidání informace o takovém kontraktu do API dokumentace by pak bylo už hračkou. Technologií, která nám tohle všechno umožní, jsou právě Code Contracts.

Instalace Code Contracts

Instalace je přímočará. Code Contracts je možné stáhnout na stránkách Microsoft Dev Labs. Pokud máte k dispozici nějakou z následujících edicí Visual Studia: Visual Studio 2008 Team System, Visual Studio 2010 Premium Edition nebo Visual Studio 2010 Ultimate Edition, pak doporučuji stáhnout Premium edici Code Contracts, protože ta obsahuje i integraci statického analyzátoru v IDE a právě statickou analýzou se v prvních dílech seriálu budeme nejvíce zabývat. Express edice Visual Studia neumožňuje integraci Code Contracts z toho prostého důvodu, že neposkytuje dostatečné rozšiřující mechanizmy. Pro všechny ostatní edice Visual Studia je určena verze Code Contracts Standard, která ale nepodporuje statickou analýzu přímo v IDE.

Code Contracts je teoreticky možné používat i bez jakékoliv podpory v IDE pouze přes příkazovou řádku. Více podrobností se dočtete v oficiální dokumentaci.

Už vám jde z těch všech edic a verzí hlava kolem? Máte jenom Express edici Visual Studia? Nebo se vám prostě nechce instalovat další add-in? Nezoufejte! Code Contracts (a nejen je) si můžete vyzkoušet online na rise4fun.

První příklad

Pojďme se podívat, jak to bude s voláním metody Substring(-42) při použítí Code Contracts. Vytvoříme standardní konzolovou aplikaci. Když klikneme pravým tlačítkem na ikonu našeho nového projektu v Solution Exploreru a vybereme "Properties", objeví se známá obrazovka s vlastnostmi projektu. Novinkou pro některé ovšem může být záložka s názvem "Code Contracts".

Pro začátek si Code Contracts nastavte tak, jak je uvedeno na obrázku, a pojďme programovat.

public class Program {
	public static void Main(string[] args) {
		var x = "Hello world".Substring(-1);
	}
}

Když tento program přeložíte, zobrazí se u volání metody Substring modrá vlnovka. O toto označení se postaral právě statický analyzátor Code Contracts. Některé metody z .NET BCL (Base Class Library) totiž již Code Contracts podporují a statický analyzátor (součást Code Contracts) se v tomto případě podíval na kontrakt metody Substring, zjistil, že hodnota -1 není validní, a upozorňuje nás.

Vytváříme vlastní kontrakty

Teď už víme, že statický analyzátor nám zkontroluje kontrakt na standardních metodách z .NET BCL. Nyní si ukážeme jak přidat kontrakt vlastní metodě nebo celému typu a předvedeme si, že kromě tzv. pre-conditions, neboli požadavků na vstupní parametry metod (startIndex u metody Substring), je možné uvést kontrakt i například pro návratovou hodnotu metody a další elementy.

Budeme postupně vytvářet třídu Fractional (zlomek) s datovými položkami numerator (čitatel) a denominator (jmenovatel). Začněme deklarací typu a konstruktoru.

public class Fractional {	
	public double Numerator { get; private set; }
	public double Denominator { get; private set; }
	
	public Fractional(int numerator, int denominator) {		
		this.Numerator = numerator;
		this.Denominator = denominator;
	}	
}

public class Program {
	public static void Main(string[] args) {
		var x = new Fractional(4, 0);
	}
}

Jak je všeobecně známo, zlomek s nulou ve jmenovateli nedává dost dobrý smysl, takže bychom chtěli přidat kontrakt, kterým dáme "vnějšímu světu" najevo, že při volání konstruktoru musí pro parametr denominator platit nerovnost denominator != 0. Jedná se o zmiňovanou pre-condition a zapisujeme ji pomocí logického výrazu, který je parametrem statické metody Requires na statické třídě Contract ze jmenného prostoru System.Diagnostics.Contract.

using System.Diagnostics.Contracts;

public class Fractional {
	// ...
	public Fractional(int numerator, int denominator) {		
		Contract.Requires(denominator != 0);		
		this.Numerator = numerator;
		this.Denominator = denominator;
	}	

Po tom, co kód přeložíme a necháme proběhnout analyzátor Code Contracts, se samozřejmě objeví známá modrá vlnovka na řádku s new Fractional(4, 0). Poučeni z chybového hlášení jej opravíme na new Fractional(4, 1).

Post-conditions

Další metodou, kterou přidáme třídě Fractional, bude statická metoda FromInt, která ze zadaného celého čísla udělá instanci třídy Fractional.

public class Fractional {
	// ....
	
	public static Fractional FromInt(int i) {
		return new Fractional(i, 1);
	}
}

public class Program {
	public static void Main(string[] args) {
		var x = Fractional.FromInt(4);
		Console.WriteLine("{0} / {1}", x.Denominator, x.Numerator);
	}
}

Co nám teď po kompilaci poví statický analyzátor? Dozvíme se, že na řádku s WriteLine může dojít k NullReferenceException. Nikdo nám totiž nezaručuje, že to, co vrátí metoda Fractional.FromInt, nemůže být null a zavolání getteru vlastnosti Denominator by v takovém případě vyvolalo uvedenou výjimku.

Statický analyzátor Code Contracts v tomto případě kontroluje i implicitní (vestavěný) kontrakt jazykového konstruktu, jakým je volání instanční metody (getteru vlastnosti). Pokud v C# zavoláme metodu na null referenci, obdržíme výjimku typu NullReferenceException. Podobně statický analyzátor kontroluje i další jazykové konstrukty a upozorňuje nás na možné chyby, jako je například dělení nulou.

Analyzátor neví nic o tom, jak metoda FromInt funguje, a neví, že nikdy nemůže vrátit null referenci. Představte si, že metoda FromInt je součástí nějaké knihovny, k jejímž zdrojovým kódům nemáte přístup, v takovém případě si tím, že FromInt nikdy nevrací null, nemůžeme být jisti!

Nyní se nacházíme v opačné situaci. Po metodě FromInt chceme nějakou garanci ohledně jejího výsledku. Konkrétně že nebude null. Tento druh kontraktu se nazývá post-condition a zapisuje se logickým výrazem, podobně jako pre-condition, na začátku dané metody. Místo Requires, které bylo u pre-condition, ovšem musíme zavolat Ensures. Možná už v tom vidíte maličký háček. Jak se odvolat na výsledek, když jej na začátku těla metody ještě nevíme? Slouží k tomu speciální funkce Contract.Result<T>(). Použití snad bude jasné z následující ukázky:

public class Fractional {
	// ....
	
	public static Fractional FromInt(int i) {
		Contract.Ensures(Contract.Result<Fractional>() != null);
		return new Fractional(i, 1);
	}
}

Tímto kódem jsme "vnějšímu světu" sdělili, že se nemusí bát, že by snad metoda FromInt vrátila null. Pokud teď znovu program zkompilujete, modrá vlnovka na řádku s WriteLine by měla zmizet.

Objektový invariant

Poslední metodou, kterou v dnešním dílu přidáme, je ToInt. ToInt by měla převést daný zlomek na nejbližší celé číslo. Tato metoda už bude instanční a její implementace by měla být snadná.

public class Fractional {
	public Fractional(int numerator, int denominator) {		
		Contract.Requires(denominator != 0);		
                // ...
	}

	// ....

	public int ToInt() {
		return this.Numerator / this.Denominator;
	}
}

Jak jistě tušíte, tento kód statickou analýzou neprojde, jinak bychom se jím nezabývali. Code Contracts nám nahlásí možnost dělení nulou. Jak to? Přeci jsme v konstruktoru uvedli, že denominator != 0. Zaručuje nám to ale, že vždy před zavoláním ToInt() bude vlastnost Denominator různá od nuly? Odpověď je: ne zcela. Stačí jenom přidat do Fractional neškodnou veřejnou metodu:

public class Fractional {
	// ....
	public void InvalidateMe() {
		this.Denominator = 0;
	}
	
	public int ToInt() {
		return this.Numerator / this.Denominator;
	}
}

public class Program {
	public static void Main(string[] args) {
		var x = Fractional.FromInt(4);
		x.InvalidateMe();
		int i = x.ToInt();
	}
}

Uvedený sled volání InvalidateMe a potom ToInt by skončil právě na dělení nulou. Co nyní potřebujeme, je objektový invariant. Objektový invariant je tvrzení, které platí po celou dobu existence objektu. U typu DateTime by například mělo vždy platit, že vlastnost Month (měsíc) je menší nebo rovna 12. U zlomku je to už obligátní denominator != 0.

Invariant se v Code Contracts zapisuje pomocí libovolně pojmenované, zpravidla privátní, metody, která je ale označena atributem [InvariantMethod] a která se skládá pouze ze sekvence volání metody Contract.Invariant - ta podobně jako Contract.Requires nebo Contract.Ensures bere jako první parametr logický výraz. Následuje názorná ukázka.

public class Fractional {
	// ....
	public void InvalidateMe() {
		this.Denominator = 0;
	}
	
	public int ToInt() {
		return this.Numerator / this.Denominator;
	}
	
	[InvariantMethod]
	private void ContractInvariant() {
		Contract.Invariant(this.Denominator != 0);
	}
}

Po této úpravě a kompilaci zmizí vlnovka u metody ToInt, ale objeví se u metody InvalidateMe, která porušuje invariant objektu, což je přesně stav, který jsme si představovali.

Závěr

V dnešním díle jsme si představili technologii Code Contracts, ukázali jsme si její základní nastavení a použití. V dalším díle se podíváme na trochu pokročilejší možnosti Code Contracts, jako například kontrakty pro výstupní parametry.

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

Hlasování bylo ukončeno    
0 hlasů
Google
Autor studuje vysokou školu a pracuje jako programátor. Zajímá se především o věci okolo platformy .NET a verifikaci programů. Kromě toho rád hraje fotbal a leze na boulderu.
Web    

Nové články

Obrázek ke článku Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Touto roční dobou, kdy je zem pokrytá barevným listím a prsty křehnou v mrazivých ránech, se obvykle těšíme na zbrusu novou verzi RAD Studia. Letos si však ale budeme muset počkat na Godzillu a Linux až do jara. Vezměme tedy za vděk alespoň updatem 2 a jelikož dle vyjádření pánů z Embarcadero se budou nové věci objevovat průběžně, pojďme se na to tedy podívat.

Reklama
Reklama
Obrázek ke článku Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Stále rostoucí zájem o cloudové služby i maximální důraz na pružnost, spolehlivost a bezpečnost IT vedou k výrazným inovacím v datových centrech. V infrastruktuře datových center hraje stále významnější roli software a stále častěji se lze setkat s hybridními přístupy k jejich budování i provozu.

Obrázek ke článku Konference: Mobilní technologie mají velký potenciál pro byznys

Konference: Mobilní technologie mají velký potenciál pro byznys

Firmy by se podle analytiků společnosti Gartner měly  rychle přizpůsobit skutečnosti, že mobilní technologie už zdaleka nejsou horkou novinkou, ale standardní součástí byznysu. I přesto - nebo možná právě proto - tu nabízejí velký potenciál. Kde tedy jsou ty největší příležitosti? I tomu se bude věnovat již čtvrtý ročník úspěšné konference Mobilní řešení pro business.

Obrázek ke článku Hackerský kongres přiveze v září do Prahy špičky světové kryptoanarchie

Hackerský kongres přiveze v září do Prahy špičky světové kryptoanarchie

Hackerský kongres HCPP16 pořádá od 30. září do 2. října nezisková organizace Paralelní Polis již potřetí, a to ve stejnojmenném bitcoinovém prostoru v pražských Holešovicích. Letos přiveze na třídenní konferenci přes 40 většinou zahraničních speakerů – lídrů z oblastí technologií, decentralizované ekonomiky, politických umění a aktivismu. Náměty jejich přednášek budou také hacking, kryptoměny, věda, svoboda nebo kryptoanarchie.

loadingtransparent (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })();
Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032016 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý