Live data from Hacker News

Use Your Type System

dzombak.com

111–120 of 357 posts

Re: Use Your Type System

#112

I've seen experienced programmers do this a lot. It's the kind of thing that someone thinks is annoying, without realizing that it was preventing them from doing something incorrect.

It can be annoying though.

I think Rich Hickey has a point that bugs like this almost certain get caught by running the program. If they make it into production it usually results in an obscure edge case.

I’m sure there are exceptions but unless you’re designing for the worst case (safety critical etc) rather than average case (web app), types come with a lot of trade offs.

I’ve been on the fence about types for a long time, but having built systems fast at a startup for years, I now believe dynamic typing is superior. Folks I know who have built similar systems and are excellent coders also prefer dynamic typing.

In my current startup we use typescript because the other team members like it. It does help replace comments when none are available, and it stops some bugs, but it also makes the codebase very hard to read and slows down dev.

A high quality test suite beats everything else hands down.

Re: Use Your Type System

#113
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.

Well yeah, because variables in what you consider to be a strongly typed language are allocating the storage for those variables. When you say int x you're asking the compiler to give you an int shaped box. When you say x = 1 in Ruby all you're doing is saying is that in this scope the name x now refers to the box holding a 1. You can't actually store a string in the int box, you can only say that from now on the name x refers to the string box.

Re: Use Your Type System

#114
post #110

The equivalent in Python is:- from typing import NewType UserId = NewType("UserId", int)

Actually, not really. In this case UserId is still an integer, which means any method that takes an integer can also take a UserId. Which means your co-workers are likely to just use integer out of habit.

Also, you can still do integer things with them, such as

> nonsense = UserId(1) + UserId(2)

Re: Use Your Type System

#115
post #107
post #25

Earlier quoted context omitted.

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…

I proposed a primitive for this in TypeScript a couple of years ago [1]. While I'm not entirely convinced myself whether it is worth the effort, it offers the ability to express "a number greater than 0". Using type narrowing and intersection types, open/closed intervals emerge naturally from that. Just check `if (a > 0 && a 0)&( I also built a simple playground that has a PoC implementation: https://nikeee.github.io…

Related https://github.com/microsoft/TypeScript/issues/54925

My specific use case is pattern matching http status codes to an expected response type, and today I'm able to work around it with this kind of construct https://github.com/mnahkies/openapi-code-generator/blob/main... - but it's esoteric, and feels likely to be less efficient to check than what you propose / a range type.

There's runtime checking as well in my implementation, but it's a priority for me to provide good errors at build time

Re: Use Your Type System

#116

Type systems, like any other tool in the toolbox, have an 80/20 rule associated with them. It is quite easy to overdo types and make working with a library extremely burdensome for little to no to negative benefit. I know what a UUID (or a String) is. I don't know what an AccountID, UserID, etc. is. Now I need to know what those are (and how to make them, etc. as well) to use your software. Maybe an elaborate type sy…

> I don't know what an AccountID, UserID, etc. is. Now I need to know what those are (and how to make them, etc. as well) to use your software. Presumably you need to know what an Account and a User are to use that software in the first place. I can't imagine a reasonable person easily understanding a getAccountById function which takes one argument of type UUID, but having trouble understanding a getAccountById func…

UserID and AccountID could just as well be integers.

What he means is that by introducing a layer of indirection via a new type you hide the physical reality of the implementation (int vs. string).

The physical type matters if you want to log it, save to a file etc.

So now for every such type you add a burden of having to undo that indirection.

At which point "is it worth it?" is a valid question.

You made some (but not all) mistakes impossible but you've also introduced that indirection that hides things and needs to be undone by the programmer.

Re: Use Your Type System

#117
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 indicates e.g. "this is just a String but it's a particular kind of String and shouldn't be mixed with other Strings".

Re: Use Your Type System

#118
post #73

Earlier quoted context omitted.

The “Stop at first level of type implementation” is where I see codebases fail at this. The example of “I’ll wrap this int as a struct and call it a UUID” is a really good start and pretty much always start there, but inevitably someone will circumvent the safety. They’ll see a function that takes a UUID and they have an int; so they blindly wrap their int in UUID and move on. There’s nothing stopping that UUID from…

> 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 don't see this having much to do with OOP vs FP but maybe the ease in which a language lets you create nominal types and functions that can nicely fail.

What sucks about OOP is that it also holds your hand into antipatterns you don't necessarily want, like adding behavior to what you really just wanted to be a simple data type because a class is an obvious junk drawer to put things.

And, like your example of a problem in FP, you have to be eternally vigilant with your own patterns to avoid antipatterns like when you accidentally create a system where you have to instantiate and collaborate multiple classes to do what would otherwise be a simple `transform(a: ThingA, b: ThingB, c: ThingC): ThingZ`.

Finally, as "correct by construction" goes, doesn't it all boil down to `createUUID(string): Maybe`? Even in an OOP language you probably want `UUID.from(string): Maybe`, not `new UUID(string)` that throws.

Re: Use Your Type System

#119
I think the rule of thumb here is to avoid every kind of runtime check that can be checked at compile time.

But if you have a function that works with different types you should make it more reusable.

It’s a good marker to yourself or to a review agent

Re: Use Your Type System

#120
There was a post a decade or more ago, I think written with Java, that used variables like "firstname", "lastname", "fullname", and "nickname" in its example, including some functions to convert between them. Does this sound familiar to anyone?

The examples were a bit less contrived than this, encoding business rules where you'd want nickname for most UI but real name for official notifications, and the type system prevented future devs from using the wrong one when adding new UI or emails.

Post reply on HN