5 ms·
I would add sructural types, for example anonymous (extensible) records and variants. Nominal types are overused in nearly all programming languages, even futur
by grumpyprole 5y ago
I would add sructural types, for example anonymous (extensible) records and variants. Nominal types are overused in nearly all programming languages, even futuristic ones like Haskell. The default type definition should be a structural type, because it is easy to then simply name it if required.
Every C or Java programmer writes a function definition in terms of a tuple of parameters, despite not having first class tuples. Functional programming languages can also return tuples, but where are the anonymous records? These would allow defining functions with named arguments essentially for free.
- yeputons 5y agoTypeScript's types are structural, and I don't consider this to be a good thing. It's useful for JavaScript interop, yes, but just because two values have the same representation and method names does not mean they're interchangeable. Case in point: time units. So while there may be some use of structural subtyping, I don't think it's codebase-wide.
- grumpyprole 5y agoHere's a counter example. I've seen numerous Java projects define a nominal predicate type, for example com.google.common.base.Predicate. None of these are interoperable without writing adapter code. ML and Haskell would essentially use a structural type: t -> bool Much simpler and easier to consume. How would you assign a nominal type to the result of a SQL query? So there are arguments on both sides. My point was that structural types can always easily be turned into a nominal type, but not the other way around. Therefore they should be the default.
- de_keyboard 5y agofunction types are structural in most nominally-typed languages I have used, perhaps a poor example?
- grumpyprole 5y agoAre you sure? What language are you referring to? For example, although Java method definitions are essentially defined in terms of tuples, function classes and objects in Java are all entirely nominal.
- _old_dude_ 5y agoThere are interoperable since Java 8, using the operator :: com.google.common.base.Predicate<String> guavaPredicate = ... java.util.function.Predicate<String> predicate = guavaPredicate::apply;
- Twisol 5y agoThe :: syntax minimizes the pain, but the fact you have to do it at all is still irritating, and IIUC it incurs a small runtime cost due to the intermediate object that's generated to convert between the two interfaces. I recently cleared out some of these intermediaries in a hot area of code and got a small but significant performance boost.
- cageface 5y agoAfter working in nominally typed languages for years I’m finding Typescript’s approach to types very liberating. I think structural typing with the option of defining nominal types is a sweet spot in type ergonomics.
- cwalv 5y agoI agree. I think part of the reason for this is that Typescript's type system was created with a goal of expressing the APIs of many existing js APIs, and many of those APIs are designed without any real constraint imposed by the type system.
- sullyj3 5y agoRight, there should be the ability to use either structural or nominal as appropriate.
- munchler 5y agoF# has anonymous records, which are great, but I definitely wouldn't want them to be the default.
- grumpyprole 5y agoThe F# ones are tacked-on and have awkward syntax, but otherwise, why not? As I said, anonymous records could permit named arguments for free, e.g. let foo {x, y} = x + y in foo {x=1, y=2} The function "foo" above has type: { x:int, y:int } -> int Again, a nominal type can always easily be created from a structural type.
- pron 5y agoThe problem with structural types are the errors. That one choice leads to a problem doesn't mean that the alternative won't have a worse one.
- grumpyprole 5y agoI want both, so I get to decide the most appropriate for my problem.
- andrewchambers 5y agoA simple solution might be to just look for name aliases that match a type and report that to the user. I don't see why you can't name the shape of a structural type without having to use nominal types.
- pron 5y agoBut you could have a dozen name aliases for a specific type. So you can name the type, but the name is no longer unique, as two names for the same structure are two names assigned to the same type.
- _old_dude_ 5y agoOne of the issue with structural types is compiler error messages. By example, C++ templates are structural types and error messages are really hard to decipher. Recent versions of Java (Java 8+) avoid structural types but provide structural conversions + inference. We will see with the recent introduction of named records/tuples goes in the same direction or not.
- ncmncm 5y agoC++ templates used to be structural types. Since C++20, C++ supports meta-type constraints on templates. Of course, backward compatibility means those are optional, but the designer of the template decides. Existing libraries are all structural, but new ones will rely more on nominal meta-typing, and error messages for those are clean. There will be pressure to retrofit older libraries, so that error messages from misuses of those get nicer too. Gripes from users who had successfully abused those libraries will be heard.
- pjmlp 5y agoPartially, because they only work for the caller, on the implementation itself, one can still make use of structural typing on top of concept constrained parameters and the compiler will be silent on that until the template gets instatiated and the traditional compiler vomit ensues.
- ncmncm 5y agoYou are just talking about when they are applied, not what can be done. Nothing was removed from C++: you can still write templates with structural constraints, or trait constraints, or any mix. In Rust, a generic is only right or wrong, in isolation. In C++, how it behaves, including whether it compiles, depends on how you choose to use it. That makes C++ templates strictly more powerful than Rust facilities. Rust could relax some restrictions, selectively, to gain that power, and might someday. Preventing the "compiler vomit" is a main selling point of Concepts, and it works. It is still possible to subvert it, if you work at that (then you are no worse off than before). So, don't.
- square_usual 5y agoElm Records and OCaml objects can be used structurally, so it's not even an unusual concept in the FP space.
- cococonut 5y agoAnd PureScript. OCaml also has polymorphic variants. Which could also be called anonymous sum types.