Live data from Hacker News

Use Your Type System

dzombak.com

161–170 of 357 posts

Re: Use Your Type System

#161
post #39

In C#, I often use a type like: 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 als…

There are libraries for that, such as Vogen https://github.com/SteveDunn/Vogen The name means "Value Object Generator" as it uses Source generation to generate the "Value object" types. That readme has links to similar libraries and further reading.

This seems like overkill. I’d prefer the few lines of code above to a whole library.

Re: Use Your Type System

#162
post #93

Earlier quoted context omitted.

> This is where the concept of “Correct by construction” comes in. This is one of the basic features of object-oriented programming that a lot of people tend to overlook these days in their repetitive rants about how horrible OOP is. One of the key things OO gives you is constructors . You can't get an instance of a class without having gone through a constructor that the class itself defines. That gives you a way to…

I find regular OOP language constructor are too restrictive. You can't return something like Result to handle the error gracefully or return a specific subtype; you need a static factory method to do something more than guaranteed successful construction w/o exception. Does this count as a missing language feature by requiring a "factory pattern" to achieve that?

This is why constructors are dumb IMO and rust way is the right way.

Nothing stops you from returning Result in CorrectObject::new(..) function because it's just a regular function struct field visibility takes are if you not being able to construct incorrect CorrectObject.

Re: Use Your Type System

#163
post #80

Earlier quoted context omitted.

There are libraries for that, such as Vogen https://github.com/SteveDunn/Vogen The name means "Value Object Generator" as it uses Source generation to generate the "Value object" types. That readme has links to similar libraries and further reading.

Have you used this in production? It seems appealing but seems so anti-thetical to the common sorts of engineering cultures I've seen where this sort of rigorous thinking does not exactly abound.

[deleted]

Re: Use Your Type System

#164

This reminds me of the mp-units [1] library which aims to solve this problem focusing on the physical quantities. The use of strong quantities means that you can have both safety and complex conversion logic handled automatically, while having generic code not tied to single set of units. I have tried to bring that to the prolog world [2] but I don't think my fellow prolog programmers are very receptive to the idea ^…

I had kind of written off using types because of the complexity of physical units, so I will be having a look at that!

My biggest problem has been people not specifying their units. On our own code end I'm constantly getting people to suffix variables with the units. But there's still data from clients, standard library functions, etc. where the units aren't specified!

Re: Use Your Type System

#165
post #38

Earlier 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 ' '

irb(main):001:0> a = 1 => 1 irb(main):002:0> a = '1' => "1" It doesn't seem that strong to me.

The types are strong. The variables are weak.

Re: Use Your Type System

#166
post #25
post #3

I 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…

in raku, that’s spelled

  subset OneToTen of Int where 1..10:

Re: Use Your Type System

#167
post #38

Earlier 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 ' '

irb(main):001:0> a = 1 => 1 irb(main):002:0> a = '1' => "1" It doesn't seem that strong to me.

It would be weak if that was actually mutating the first “a”. That second declaration creates a new variable using the existing name “a”. Rust lets you do the same[1].

[1] https://doc.rust-lang.org/book/ch03-01-variables-and-mutabil...

Re: Use Your Type System

#168

Earlier quoted context omitted.

This can be done in typescript. It’s not super well known because of typescripts association with frontend and JavaScript. But typescript is a language with one of the most powerful type systems ever. Among the popular languages like golang, rust or python typescript has the most powerful type system. How about a type with a number constrained between 0 and 10? You can already do this in typescript. type onetonine =…

Complexity is bad in software. I think this kind of thing does more harm than good. I get an error that I can't assign something that seems to me assignable, and to figure out why I need to study functions at type level using tuples and recursion. The cure is worse than the disease.

It can work. It depends on context. Like let's say these types are from a well renowned library or one that's been used by the codebase for a long time.

If you trust the type, then it's fine. The code is safer. In the world of of the code itself things are easier.

Of course like what you're complaining about, this opens up the possibility of more bugs in the world of types, and debugging that can be a pain. Trade offs.

In practice people usually don't go crazy with type level functions. They can do small stuff, but usually nothing super crazy. So type script by design sort of fits the complexity dynamic you're looking for. Yes you can do type level functions that are super complex, but the language is not designed around it and it doesn't promote that style either. But you CAN go a little deeper with types then say a language with less power in the type system like say Rust.

Re: Use Your Type System

#169
post #152

Swift has a typealias keyword but it's not really useful for this since two distinct aliased types with the same underlying type can be freely interchanged. Wrong code may look wrong but it will still compile. Wrapper structs are the idiomatic way to achieve this, and with ExpressibleByStringLiteral are pretty ergonomic, but I wonder if there's a case for something like a "strong" typealias ("typecopy"?) that indicat…

Haskell has this, it's called newtype. In OOP languages as long as the type you want to specialize isn't final you can just create a subclass. It's cheap (no additional wrappers or boxes), easy, and you can specialize behavior if you want to. Unfortunately for various good reasons Java makes String final, and String is one of the most useful types to specialize on.

But then you are representing two distinct types as the same underlying type, String.

  MyType extends String;
  void foo(String s);
  foo(new MyType()); // is valid
Leading to the original problem. I don't want to represent MyType as a String because it's not.
Post reply on HN