Unfortunately, this can be somewhat awkward to implement in certain structural typed languages like TypeScript. I often find myself writing something along the lines of type UserID = string & { readonly __tag: unique symbol } which always feels a bit hacky.
Use Your Type System
31–40 of 357 posts
Re: Use Your Type System
#32I like this. Very much falls into the "make bad state unrepresentable". The issues I see with this approach is when developers stop at this first level of type implementation. Everything is a type and nothing works well together, tons of types seem to be subtle permutations of each other, things get hard to reason about etc. In systems like that I would actually rather be writing a weakly typed dynamic language like…
Yep. For this reason, I wish more languages supported bound integers. Eg, rather than saying x: u32, I want to be able to use the type system to constrain x to the range of [0, 10). This would allow for some nice properties. It would also enable a bunch of small optimisations in our languages that we can't have today. Eg, I could make an integer that must fall within my array bounds. Then I don't need to do bounds ch…
Re: Use Your Type System
#33I'm not familiar with Go. Please correct me, but this reads like object oriented programming i.e. OOP for every kind of data? Coming from C++, this kind of types with classes make sense. But also are a maintenance task with further issues, were often proper variable naming matters. Likely a good balance is the key.
That is, this is perfectly acceptable C:
int x = 10;
myId id = x; // no problems
In Go the equivalent would be an error because it will not, automatically, convert from one type to another just because it happens to be structurally identical. This forces you to be explicit in your conversion. So even though the type happens to be an int, an arbitrary int or other types which are structurally ints cannot be accidentally converted to a myId unless you somehow include an explicit but unintended conversion.Re: Use Your Type System
#34Earlier quoted context omitted.
FYI: Ruby is strongly typed, not loosely. > 1 + "1" (irb):1:in 'Integer#+': String can't be coerced into Integer (TypeError) from (irb):1:in ' ' from :168:in 'Kernel#loop' from /Users/george/.rvm/rubies/ruby-3.4.2/lib/ruby/gems/3.4.0/gems/irb-1.14.3/exe/irb:9:in ' ' from /Users/george/.rvm/rubies/ruby-3.4.2/bin/irb:25:in 'Kernel#load' from /Users/george/.rvm/rubies/ruby-3.4.2/bin/irb:25:in ' '
There seem to be two competing nomenclatures around strong/weak typing where people mean static/dynamic instead.
Static typing / dynamic typing refers to whether types are checked at compile time or runtime. "Static" = compile time (eg C, C++, Rust). "Dynamic" = runtime (eg Javascript, Ruby, Excel)
Strong / weak typing refers to how "wibbly wobbly" the type system is. x86 assembly language is "weakly typed" because registers don't have types. You can do (more or less) any operation with the value in any register. Like, you can treat a register value as a float in one instruction and then as a pointer during the next instruction.
Ruby is strongly typed because all values in the system have types. Types affects what you can do. If you treat a number like its an array in ruby, you get an error. (But the error happens at runtime because ruby is dynamically typed - thus typechecking only happens at runtime!).
Re: Use Your Type System
#35Earlier quoted context omitted.
To be fair, you probably needed to know that anyway? Or else you would've just passed invalid data into functions.
I cannot recall ever passing an invalid UUID (or long id) into a function due to statically-knowable circumstances.
I generally agree that it's easy to over-do, but can be great if you have a terse, dense, clear language/framework/docs, so you can instantly learn about UserID.
Re: Use Your Type System
#36Does anyone know the term for this? I had "Type Driven Development" in my head, but I don't know if that's a broadly used term for this. It's a step past normal "strong typing", but I've loved this concept for a while and I'd love to have a name to refer to it by so I can help refer others to it.
Re: Use Your Type System
#37Re: Use Your Type System
#38I like this. Very much falls into the "make bad state unrepresentable". The issues I see with this approach is when developers stop at this first level of type implementation. Everything is a type and nothing works well together, tons of types seem to be subtle permutations of each other, things get hard to reason about etc. In systems like that I would actually rather be writing a weakly typed dynamic language like…
FYI: Ruby is strongly typed, not loosely. > 1 + "1" (irb):1:in 'Integer#+': String can't be coerced into Integer (TypeError) from (irb):1:in ' ' from :168:in 'Kernel#loop' from /Users/george/.rvm/rubies/ruby-3.4.2/lib/ruby/gems/3.4.0/gems/irb-1.14.3/exe/irb:9:in ' ' from /Users/george/.rvm/rubies/ruby-3.4.2/bin/irb:25:in 'Kernel#load' from /Users/george/.rvm/rubies/ruby-3.4.2/bin/irb:25:in ' '
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a = '1'
=> "1"
It doesn't seem that strong to me.Re: Use Your Type System
#39 readonly struct Id32 {
public readonly int Value { get; }
}
Then you can do: public sealed class MFoo { }
public sealed class MBar { }
And: Id32 x;
Id32 y;
This gives you integer ids that can’t be confused with each other. It can be extended to IdGuid and IdString and supports new unique use cases simply by creating new M-prefixed “marker” types which is done in a single line.I’ve also done variations of this in TypeScript and Rust.
Re: Use Your Type System
#40I think Rich Hickey was completely right, this is all information and we just need to get better at managing information like we are supposed to.
The downside of this approach is that these systems are tremendously brittle as changing requirements make you comfort your original data model to fit the new requirements.
Most OOP devs have seen atleast 1 library with over 1000 classes. Rust doesn't solve this problem no matter how much I love it. Its the same problem of now comparing two things that are the same but are just different types require a bunch of glue code which can itself lead to new bugs.
Data as code seems to be the right abstraction. Schemas give validation a-la cart while still allowing information to be passed, merged, and managed using generic tools rather than needing to build a whole api for every new type you define in your mega monolith.