Also relevant https://refactoring.guru/smells/primitive-obsession
Use Your Type System
121–130 of 357 posts
Re: Use Your Type System
#122Unfortunately, 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.
I think it's a much better idea to do:
type UserID = { readonly __tag: unique symbol }
Now clients of `UserID` no longer knows anything about the representation. Like with the original approach you need a bit of casting, but that can be neatly encapsulated as it would be in the original approach anyway.Re: Use Your Type System
#123Earlier 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…
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 =…
I'll take a modern hindley milner variant any day. Sophisticated enough to model nearly any type information you'll have need of, without blurring the lines or admitting the temptation of encoding complex logic in it.
Re: Use Your Type System
#124An adjacent point is to use checked exceptions and to handle them appropriate to their type. I don't get why Java checked exceptions were so maligned. They saved me so many headaches on a project where I forced their use as I was the tech lead for it. Everyone hated me for a while because it forced them to deal with more than just the happy path but they loved it once they got in the rhythm of thinking about all the…
Checked exceptions feel like a bad mix of error returns and colored functions to me.
Re: Use Your Type System
#125Swift 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…
I guess the examples in TFA are golang? It's kind of nice that you don't have to define those wrapper types, they do make things a bit more annoying.
In C++ you have to be extra careful even with wrapper classes, because types are allowed to implicitly convert by default. So if Foo has a constructor that takes a single int argument, then you can pass an int anywhere Foo is expected. Fine as long as you remember to mark your constructors as explicit.
Re: Use Your Type System
#126Swift 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…
Re: Use Your Type System
#127 type UserId = string & { readonly __tag: unique symbol };
In Python you can use `NewType` from the typing module: from typing import NewType
from uuid import UUID
UserId = NewType("UserId", UUID)Re: Use Your Type System
#128This technique makes me sad. Not because it's a bad idea. Quite the contrary. I've sung the praises of it myself. But because it's like the most basic way you can use a type system to prevent bugs. In both the sense used in the article, and in the sense that it is something you have to do to get the even more powerful tools brought to bear on the problem that type systems often. And yet, in the real world, I am const…
Re: Use Your Type System
#129Earlier quoted context omitted.
I've recently been following red-green-refactor but instead of with a failing test, I tighten the screws on the type system to make a production-reported bug cause the type checker to fail before making it green by fixing the bug. I still follow TDD-with-a-test for all new features, all edge cases and all bugs that I can't trigger failure by changing the type system for. However, red-green-refactor-with-the-type-syst…
I found myself following a similar trajectory, without realizing that’s what I was doing. For a while it felt like I was bypassing the discipline of TDD that I’d previously found really valuable, until I realized that I was getting a lot of the test-first benefits before writing or running any code at all. Now I just think of types as the test suite’s first line of defense. Other commenters who mention the power of t…
However, Im convinced that theyre both part of the same class of thing, and that "TDD" or red/green/refactor or whatever you call it works on that class, not specifically just on tests.
Documentation is a funny one too - I use my types to generate API and other sorts of reference docs and tests to generate how-to docs. There is a seemingly inextricable connection between types and reference docs, tests and how-to docs.
Re: Use Your Type System
#130Swift 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…
Yeah, most languages I've used are like this. E.g. rust/c/c++. I guess the examples in TFA are golang? It's kind of nice that you don't have to define those wrapper types, they do make things a bit more annoying. In C++ you have to be extra careful even with wrapper classes, because types are allowed to implicitly convert by default. So if Foo has a constructor that takes a single int argument, then you can pass an i…