Typ (Type)
Typ bardzo przypomina klasę, która posiada właściwości, metody i zdarzenia. W dalszej części nazwy klasa i typ będą używane zamiennie.
Na listingu 1 przedstawiony jest sposób definiowania klasy.
// Class definition: type [access-modifier] type-name [type-params] [access-modifier] ( parameter-list ) [ as identifier ] = [ class ] [ inherit base-type-name(base-constructor-args) ] [ let-bindings ] [ do-bindings ] member-list ... [ end ]
Listing 1: Definicja klasy/typu w języku F#
W powyższej składni, identyfikator type-name jest nazwą klasy zgodną ze specyfikacją F#. Opcjonalne ogólne(generyczne) parametry można wstawić w miejscu type-params. Można to zrobić poprzez umieszczenie w nawiasach ostrych ( < i > ) nazw typu parametru. Kolejnym elementem jest parameter-list, czyli lista parametrów konstruktora.
Pierwszy modyfikator dostępu access-modifier odnosi się do typu, drugi natomiast odnosi się do podstawowego konstruktora. W obu przypadkach domyślny modyfikator dostępu to public.
Poniżej na listingu 2 znajduje się prosty przykład definiowania klasy z generyczną nazwą typu ‘a oraz jednym argumentem w konstruktorze o nazwie x typu ‘a.
type MyGenericClass<'a> (x: 'a) =
Listing 2: Prosty przykład deklaracji typu
Za pomocą słowa kluczowego inherit można wskazać klasę bazową, po której się dziedziczy. Trzeba wtedy podać argumenty dla konstruktora klasy bazowej.
W klasie można deklarować lokalne pola lub funkcje w części let-bindings. Sekcja do-bindings zawiera kod wykonywany podczas konstruowania obiektu.
W obszarze member-list można definiować dodatkowe konstruktory, statyczne metody, interfejsy, właściwości czy zdarzenia.
Słowo kluczowe identifier jest używane opcjonalnie i nadaje nazwę instancji. Jest identyfikatorem samego siebie i dzięki niemu można odwoływać się w definicji typu do instancji typu.
Definicję klasy można opcjonalnie rozpocząć i zakończyć słowami kluczowymi class i end.
Typ dodatkowo można zdefiniować, jako wzajemnie rekurencyjny, ale nie zostało to zaimplementowane w opracowanym narzędziu.
Poniżej na rysunku 1 przedstawiony został element języka modelowania, który symbolizuje typ/klasę.
Na poniższym prostym przykładzie (rysunek 2) widać klasę o nazwie TypeClassElement. Konstruktor przyjmuje trzy parametry x i z podstawowego typu int oraz parametr y podstawowego typu float. Klasa nie zawiera żadnych elementów w sekcjach Attributes i Operations.
Na rysunku 3 przedstawione są możliwe do ustawienia właściwości dla typu/klasy.
Właściwości, które są dostępne dla tego elementu to:
- Nazwa typu/klasy
- Identyfikator
- Abstrakcyjność klasy
- Lista parametrów konstruktora
- Klasa bazowa, do której możemy stworzyć relację generalizacji
- Modyfikator dostępu klasy/typu
- Generyczny typ parametru
Właściwość nazwa typu/klasy (podczas modelowania nazwa ta jest widoczna, jako Name) powinna być zgodna ze specyfikacją języka F#.
Identyfikator we właściwościach elementu nazwany jest Identifier. Można opcjonalnie wpisać nazwę instancji. Dla powyższego przykładu jest to nazwa self.
Inną właściwością jest Abstrakcyjność klasy. W języku modelowania nazwana jest jako Is Abstract. Tutaj można ustawić wartość True w przypadku gdy chcemy aby klasa była abstrakcyjna lub False w przeciwnym przypadku.
W Liście parametrów konstruktora, czyli w Name Type List możemy definiować kolejne parametry konstruktora w sposób podobny jak to było przedstawione w przypadku kolejnych parametrów funkcji.
We właściwości Klasa bazowa można ustawiać klasę, do której ma zostać stworzona relacja dziedziczenia, czyli generalizacji. Właściwość ta ma nazwę Target.
Kolejnym elementem w oknie Properties jest właściwość odnosząca się do ustawienia Modyfikatora dostępu klasy/typu. Jest ona w modelu nazwana Type Accessibility. Możliwości są identyczne jak w przypadku ustawiania modyfikatora dostępu dla modułu. Zostało to opisane w poście opisującym element języka modelowania jakim jest moduł.
Ostatnią możliwą właściwością dla elementu Type jest właściwość Generyczny typ parametru, czyli Type Generic Params.
Na listingu 3 poniżej przedstawiony został szkielet kodu źródłowego w języku F# wygenerowany dla właściwości ustawionych jak powyżej. Jest to szkielet kodu źródłowego, do którego mogą dojść kolejne elementy takie jak Attributes lub Operations, które zostaną przedstawione w kolejnych postach. W szkielecie wygenerowanego kodu źródłowego czasami użytkownik musi nanieść ręcznie poprawki, aby dostosować program do swoich potrzeb.
type public TypeClassElement<'a> (x : int,y : float,z : int) as self =
Listing 3: Prosty przykład dla typu
W ciele klasy można umieszczać wiele różnych elementów, są to między innymi:
- Sekcja let (ang. let-bindings)
- Sekcja do (ang. do-bindings)
- Właściwości (ang. Properties)
- Właściwości indeksowane (ang. Indexed Properties)
- Metody (ang. Methods)
- Konstruktory (ang. Constructors)
- Przeciążenia operatorów (ang. Operator Overloading)
- Zdarzenia (ang. Events)
W ramach opracowanego narzędzia udało się stworzyć automatyczny generator kodu źródłowego, który jest zdefiniowany tylko dla najważniejszych elementów. Są to sekcja let i do oraz właściwości oraz metody. Pozostałe elementy należy uzupełniać ręcznie w wygenerowanym szkielecie kodu źródłowego. W przyszłych wersjach wtyczki do produktu Microsoft Visual Studio 2010 można poszerzyć zakres generowanego kodu źródłowego o pozostałe elementy.