4 ms·
From https://luau-lang.org/typecheck https://luau-lang.org/typecheck > Luau’s type system is structural by default I think that makes it the second (productio
by sizediterable 5y ago
From https://luau-lang.org/typecheck https://luau-lang.org/typecheck
> Luau’s type system is structural by default
I think that makes it the second (production-ready) language to have a primarily-structural type system, after TypeScript/Flow(/and Closure to some extent) for JS. I wonder if it will follow in their impressive footsteps or if it will tread new territory.
One of the things that Flow gets right that TypeScript doesn't yet support is switching to nominal type-checking between class instances. In TypeScript you can assign an instance of one class to an instance of another as long as they have compatible fields. Compare:
Flow: https://bit.ly/3jZx4rB https://bit.ly/3jZx4rB
TS: https://tsplay.dev/mZaL1N https://tsplay.dev/mZaL1N
TypeScript doesn't have any understanding of prototypes or prototypal inheritance, which is a big gap considering that it's a fundamental aspect of JS.
I'm really hoping Luau will come to do the right thing with tables and prototypes. Perhaps it already does, but unfortunately there doesn't seem to be a Luau playground to try in the browser.
- bajsejohannes 5y agoPony, amusingly, has both structural and nominal typing. https://tutorial.ponylang.io/types/traits-and-interfaces.html https://tutorial.ponylang.io/types/traits-and-interfaces.htm...
- Someone 5y agoSo has COBOL, sort-of. A regular MOVE is sort-of structural. It moves field i of the source to field i of the destination. Source and destination need not be of the same type, though. MOVE CORRESPONDING is nominal. It moves field Foo of the source to field Foo of the destination (leaving fields that do not have corresponding items alone) In both cases, data may be converted, for example from alphabetic to alphanumeric.
- deleted 5y ago[deleted]
- dgb23 5y agoWhat about Go and OCaml? And I'm sure there are others.
- sizediterable 5y agoI forgot about OCaml (since I normally associate it with the more sophisticated typing stuff). I don't know if I'd completely count Go since interfaces only apply to methods, not fields
- dgb23 5y agoDisclaimer: Not a regular Go user. I was thinking of how you can embed types in structs. You automatically dereference the fields and methods of the components directly from the outside.
- BobbyJo 5y agoYep, in go the inheritance (using the term loosely) structure can apply to interfaces (which specify groups of functions) and structs (which specify groups of data) and roughly does the same thing in both instances.
- Zababa 5y agoI think OCaml isn't just structural. For example, sum types (variants in OCaml) have a nominal form which is the default: https://ocaml.org/manual/coreexamples.html#s%3Atut-recvariants https://ocaml.org/manual/coreexamples.html#s%3Atut-recvarian..., but also a structural form, polymorphic variants: https://ocaml.org/manual/polyvariant.html https://ocaml.org/manual/polyvariant.html. I think it's the same for records, I didn't find a way to express the type "a record that has a certain field" as an argument of a function. You can do this with objects and modules I think, but not with records.
- lapinot 5y agoStructural records are in fact "object types" in ocaml, which you can get the shell to tell you by calling a random method name. # let f x : int = x#foo;; val f : < foo : int; .. > -> int = <fun> Actually there is not really a type of "a record that has at least some fields": # type t = < foo : int; .. >;; Error: A type variable is unbound in this type declaration. In type < foo : int; .. > as 'a the variable 'a is unbound Its hidden (row) polymorphism, it's not subtyping but type abstraction. We're implicitely quantifying over the actual type: # type 'a t = < foo : int; .. > as 'a;; type 'a t = 'a constraint 'a = < foo : int; .. > For the record (ha!), for people who don't know ocaml here are "structural sum types", or polymorphic variants as we call them. # let x = `Bar;; val x : [> `Bar ] = `Bar above: type of `Bar is a sum containing "at least" (polymorphic) `Bar # type int_opt = [ `Some of int | `None ];; type int_opt = [ `None | `Some of int ] above: some "exact" nameless sum type, with arguments # type 'a t = [< `Foo | `Bar ] as 'a;; type 'a t = 'a constraint 'a = [< `Bar | `Foo ] above: polymorphic type of sums which contain at most these two constructors. refs: https://dev.realworldocaml.org/objects.html https://dev.realworldocaml.org/objects.html https://dev.realworldocaml.org/variants.html#polymorphic-variants https://dev.realworldocaml.org/variants.html#polymorphic-var...
- wwwigham 5y ago> In TypeScript you can assign an instance of one class to an instance of another as long as they have compatible fields. Fun fact: If you add a private field to a class it'll behave nominally in TS. This is because private fields kinda require nominal relations to function. So, in a way, it does support "switching" to nominal type checking for classes - the opt in is simply per-class.
- mirekrusin 5y agoIt won't do variance [0] right, will it? [0] https://flow.org/en/docs/lang/variance/ https://flow.org/en/docs/lang/variance/
- sizediterable 5y agoI think variance can be simulated by typing the private field as an existing covariant/contravariant/invariant type class CovariantFoo<T> { private phantom!: T } class ContravariantFoo<T> { private phantom!: (_: T) => void } class InvariantFoo<T> { private phantom!: (_: T) => T } (inspired by Rust [0]) [0] https://doc.rust-lang.org/nomicon/phantom-data.html https://doc.rust-lang.org/nomicon/phantom-data.html
- mirekrusin 5y agoBut variance depends on position where the value is used, not at the time of declaration, superclass/subclass at parameter/return value position can't be correctly encoded like this, can it?
- sizediterable 5y agoI think most languages define variance at type definition level, notable exceptions being Kotlin which supports both [0][1] and Flow. But yeah, TS doesn't support (variable-)declaration-site variance which I didn't realize you were asking in my previous answer. [0] https://kotlinlang.org/docs/generics.html#variance https://kotlinlang.org/docs/generics.html#variance [1] https://kotlinlang.org/docs/generics.html#declaration-site-variance https://kotlinlang.org/docs/generics.html#declaration-site-v...
- implicit 5y agoLuau already has some notion of nominal types to deal with the fact that the Roblox API is basically a ton of C++ classes that have been mapped over via the FFI. Some of these types are totally structurally identical and yet incompatible. We'd like to afford the same kind of ideas for native Luau code, but we're not there yet.
- jwatte 5y agoSuper happy to see this released, and also for all the kids getting started programming on Roblox learning that there is a better way than random tag-checked mush :-) Good on you all!
- IshKebab 5y ago> a big gap considering that it's a fundamental aspect of JS. To be fair to Typescript, it's an insane fundamental aspect of JS.
- Zababa 5y agoFunny that you would mention that in a thread on a statically-typed language based on Lua. Don't you need some insane mechanism to be flexible at runtime anyways? Either it will be reflection, or something like prototypes (in OO languages).
- oconnor0 5y ago> I think that makes it the second (production-ready) language to have a primarily-structural type system I assume we are talking about a static type system here? Many common "scripting" languages are structurally typed - what Python calls duck typing.