System typu strukturalnego - Structural type system

System typ strukturalny (lub układ typu nieruchomość oparte ) jest główną klasą systemów typu , w których zgodność rodzaju i równoważności zostały określone przez rodzaj za rzeczywistej struktury lub definicji, a nie innych cech, takich jak jego nazwa lub miejsce deklaracji. Systemy strukturalne służą do określania, czy typy są równoważne i czy typ jest podtypem innego. Kontrastuje to z systemami mianownikowymi , w których porównania oparte są na nazwach typów lub wyraźnych deklaracjach, oraz duck typing , w którym tylko część struktury, do której uzyskuje się dostęp w czasie wykonywania, jest sprawdzana pod kątem zgodności.

Opis

W typowaniu strukturalnym element jest uważany za zgodny z innym, jeśli dla każdej cechy w typie drugiego elementu istnieje odpowiadająca i identyczna cecha w typie pierwszego elementu. Niektóre języki mogą różnić się szczegółami, na przykład określeniem, czy funkcje muszą się zgadzać pod względem nazwy. Ta definicja nie jest symetryczna i obejmuje zgodność podtypów. Dwa typy są uważane za identyczne, jeśli każdy z nich jest kompatybilny z drugim.

Na przykład OCaml używa typowania strukturalnego w metodach zgodności typów obiektów. Go używa typowania strukturalnego w metodach w celu określenia zgodności typu z interfejsem. Funkcje szablonu C++ wykazują typowanie strukturalne na argumentach typu. Haxe używa typowania strukturalnego, ale klasy nie są podtypami strukturalnymi.

W językach, które obsługują polimorfizm podtypów , można utworzyć podobną dychotomię na podstawie tego, jak zdefiniowana jest relacja podtypów. Jeden typ jest podtypem innego wtedy i tylko wtedy, gdy zawiera wszystkie cechy typu podstawowego lub jego podtypów. Podtyp może zawierać dodatkowe cechy, takie jak składowe nieobecne w typie podstawowym lub silniejsze niezmienniki.

Istnieje rozróżnienie między podstawieniem strukturalnym dla wnioskowanego i niewnioskowanego polimorfizmu. Niektóre języki, takie jak Haskell , nie zastępują strukturalnie w przypadku zadeklarowania oczekiwanego typu (tj. nie są wywnioskowane), np. zastępują tylko funkcje, które są polimorficzne oparte na sygnaturze poprzez wnioskowanie o typie. Wtedy nie jest możliwe przypadkowe podtypowanie typu niewnioskowanego, chociaż nadal może być możliwe zapewnienie jawnej konwersji na typ niewnioskowany, który jest wywoływany niejawnie.

Podtypy strukturalne są prawdopodobnie bardziej elastyczne niż podtypy imienne , ponieważ umożliwiają tworzenie typów i protokołów ad hoc ; w szczególności pozwala na stworzenie typu, który jest nadtypem istniejącego typu, bez modyfikowania definicji tego ostatniego. Jednak może to nie być pożądane, gdy programista chce tworzyć zamknięte abstrakcje.

Pułapką typowania strukturalnego w porównaniu z typowaniem mianownikowym jest to, że dwa oddzielnie zdefiniowane typy przeznaczone do różnych celów, ale przypadkowo mające te same właściwości (np. oba składające się z pary liczb całkowitych), mogą być uważane za ten sam typ przez system typów, po prostu dlatego, że mają identyczną strukturę. Jednym ze sposobów uniknięcia tego jest utworzenie jednego typu danych algebraicznych dla każdego zastosowania.

W 1990 roku Cook i wsp. wykazali, że dziedziczenie nie jest podtypowaniem w językach OO o typach strukturalnych.

Przykład

Obiekty w OCaml są strukturalnie typowane według nazw i typów ich metod.

Obiekty można tworzyć bezpośrednio ( obiekty bezpośrednie ) bez przechodzenia przez klasę nominatywną. Klasy służą jedynie jako funkcje do tworzenia obiektów.

 # let x =
     object
       val mutable x = 5
       method get_x = x
       method set_x y = x <- y
     end;;
 val x : < get_x : int; set_x : int -> unit > = <obj>

Tutaj interaktywne środowisko uruchomieniowe OCaml drukuje wywnioskowany typ obiektu dla wygody. Jego typ ( < get_x : int; set_x : int -> unit >) jest określony tylko przez jego metody. Innymi słowy, typ x jest zdefiniowany przez typy metod "get_x : int" i "set_x : int -> unit", a nie przez jakąkolwiek nazwę.

Aby zdefiniować inny obiekt, który ma te same metody i typy metod:

 # let y =
     object
       method get_x = 2
       method set_x y = Printf.printf "%d\n" y
     end;;
 val y : < get_x : int; set_x : int -> unit > = <obj>

OCaml uważa je za ten sam typ. Na przykład operator równości jest wpisywany, aby przyjmować tylko dwie wartości tego samego typu:

 # x = y;;
 - : bool = false

Muszą więc być tego samego typu, inaczej nie byłoby to nawet sprawdzanie typu. To pokazuje, że równoważność typów ma charakter strukturalny.

Można zdefiniować funkcję, która wywołuje metodę:

 # let set_to_10 a = a#set_x 10;;
 val set_to_10 : < set_x : int -> 'a; .. > -> 'a = <fun>

Wywnioskowany typ pierwszego argumentu ( < set_x : int -> 'a; .. >) jest interesujący. Te ..środki, pierwszy argument może być dowolny obiekt, który ma „set_x” metody, która jest int jako argument.

Więc może być użyty na obiekcie x:

 # set_to_10 x;;
 - : unit = ()

Można utworzyć inny obiekt, który ma tę metodę i typ metody; inne metody są nieistotne:

 # let z =
     object
       method blahblah = 2.5
       method set_x y = Printf.printf "%d\n" y
     end;;
 val z : < blahblah : float; set_x : int -> unit > = <obj>

Działa na nim również funkcja „set_to_10”:

 # set_to_10 z;;
 10
 - : unit = ()

To pokazuje, że kompatybilność dla rzeczy takich jak wywoływanie metod jest określona przez strukturę.

Zdefiniujmy synonim typu dla obiektów z tylko metodą „get_x” i bez innych metod:

 # type simpler_obj = < get_x : int >;;
 type simpler_obj = < get_x : int >

Obiekt xnie jest tego typu; ale strukturalnie xnależy do podtypu tego typu, ponieważ xzawiera nadzbiór swoich metod. xMożna więc zmusić do tego typu:

 # (x :> simpler_obj);;
 - : simpler_obj = <obj>
 # (x :> simpler_obj)#get_x;;
 - : int = 10

Ale nie obiekt z, ponieważ nie jest to podtyp strukturalny:

# (z :> simpler_obj);;
This expression cannot be coerced to type simpler_obj = < get_x : int >;
it has type < blahblah : float; set_x : int -> unit > but is here used with type
  < get_x : int; .. >
The first object type has no method get_x

To pokazuje, że kompatybilność dla rozszerzających się przymusów ma charakter strukturalny.

Bibliografia

Zewnętrzne linki