The critical problem with structural typing is that it requires weird and arbitrary branding when dealing with unions of singletons.
The critical problem with structural typing is that it requires weird and arbitrary branding when dealing with unions of singletons.
Branding doesn't need to be weird and arbitrary, see Pythons NewType: https://docs.python.org/3/library/typing.html#typing.NewType
Reading TFA now, Pythons NewType seems to be equal to Haskells newtype. Yes, it's a hack for the type checker to work around existing language semantics and feels unergonomic at times when Parse, Don't Validate needs to fall back to plain validation, but I wouldn't call it neither weird nor arbitrary.
Python defaults uses nominal typing so isn't prone to this problem anyway.
The kind of "branding" I'm talking about is a hack only needed for structural typing systems. Consider something inspired by the C locale API, for example:
In a structural typing system, it is impossible to write a function that takes a union including more than one of `{NO_LOCALE, THREAD_LOCALE, GLOBAL_LOCALE, ENV_LOCALE}`, since they have no contents and thus cannot be distinguished. You have to hack around it, by some kind of casting and/or adding a member that's not actually present/useful at runtime.And this kind of need is quite common. So I maintain that structural typing is not a serious type system proposal.
(Then again, the man proponent for structural typing is TypeScript, which even in $CURRENTYEAR still lacks even a way to specify ubiquitous needs like "integer" or "valid array index").
I think a type system that permits a type (no_locale=()) | (thread_locale=()) | (global_locale=()) | (env_locale=()) would generally be considered structural. I think newtypes and structure field names are isomorphic in functionality. Where a nominal type system would use newtype(tag,X) a structural one could use struct{tag:X} (and this holds even if X is the unit/singleton type).
You mean like if you have two types which are identical but you want your type system to treat them as distinct? To me that's a data modelling issue rather than something wrong with the type system, but I understand how it can sometimes be unavoidable and you need to work around it.
I think it also makes more sense in immutable functional languages like clojure. Oddly enough I like it in Go too, despite being very different from clojure.
If I understand you correctly - in popular structurally typed languages, sure.
It seems ok in upcoming languages with polymorphic sum types (eg Roc “tags”) though?