5 ms·
> In most languages, doing what this article describes is quite straightforward Well, no. In most languages you wind up making a typed wrapper object/class tha
by beeboobaa3 2y ago
> In most languages, doing what this article describes is quite straightforward
Well, no. In most languages you wind up making a typed wrapper object/class that holds the primitive. This works fine, you can just do that in TypeScript too.
The point of branded types is that you're not introducing a wrapper class and there is no trace of this brand at runtime.
- JonChesterfield 2y agoThere's never any trace of typescript types at runtime.
- mistercow 2y agoIf you wrapped the value to give it a “brand”, the wrapper would still exist at runtime. The technique in the article avoids that.
- aidos 2y agoBy “trace” I think GP meant that the required wrapper is still there at runtime but was only in service of the type system.
- mattstir 2y agoI think what they meant is that at runtime, you don't end up with objects that look something like: { "brand": "Hash", "value": "..." } which would be the case if you used the more obvious wrapper route. Using this branding approach, the branded values are exactly the same at runtime as they would be if they weren't branded.
- recursive 2y agoWell, enums.
- DanielHB 2y agoI see where you are coming from but you are not quite understanding what the OP was saying class A { public value: number } class B { public value: number } const x: A = new B() // no error This is structural typing (shape defines type), if typescript had nominal typing (name defines type) this would give an error. You could brand these classes to forcefully cause this to error. Branding makes structural typing work like nominal typing for the branded type only. It is more like "doing what this article describes" is the default behaviour of most languages (most languages use nominal typing).
- bradrn 2y agoIndeed, this is what I was trying to say!
- DanielHB 2y agoyeah this is such a common misconception, but give the class example I showed and people just get it. "structural typing" and "nominal typing" are still quite new terms for most devs
- deleted 2y ago[deleted]
- quonn 2y agoThe article describes making "number" a different type, not A and B. It's true that making A and B different is a unique problem of TypeScript, but making number a different type is a common issue in many languages.
- DanielHB 2y agonumber is a primitive, branding a primitive can be done like in the example. To brand a class you could also add a private field. Some languages all values are objects and in those languages then the branding argument applies the same way. For languages with nominal typing and primitives you need to box the type yes. Regardless the core of the issue is understanding how structural typing works vs nominal typing
- dunham 2y ago> For languages with nominal typing and primitives you need to box the type yes. But the compiler can elide the box for you. Haskell and Idris do this. Haskell's newtype gives a nominal wrapper around a type without (further) boxing at at runtime. It is erased at compile time. Haskell does box their primitives, but via optimization they are used unboxed in some cases (like inside the body of a function). This technique could be applied to a language that doesn't box its primitives. Idris also does this for any type that is shaped like a newtype (one data constructor, one argument). In that case, both on the scheme and javascript backend, a newtyped Int are represented as "bare" numbers. E.g. with: type Foo = MkFoo Int a `MkFoo 5` value is just `5` in the generated javascript or scheme code.
- skybrian 2y agoDepends what you mean by "most languages." I think it's clearer to say which languages have zero-overhead custom types. Go has it. Java didn't used to have it so you would use wrapper classes, but I haven't kept up with Java language updates.
- beeboobaa3 2y agoJava does not have it yet. Project Valhalla might bring it with Value types.