Shoutout to the absolutely awesome beartype for python. With simple decorators it adds runtime type checking with virtually no performance cost!! https://beartype.readthedocs.io/en/latest/ Or see their page about performance: https://beartype.readthedocs.io/en/latest/faq/#faq-realtime
Use Your Type System
281–290 of 357 posts
Re: Use Your Type System
#282This 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
#283Shoutout to the absolutely awesome beartype for python. With simple decorators it adds runtime type checking with virtually no performance cost!! https://beartype.readthedocs.io/en/latest/ Or see their page about performance: https://beartype.readthedocs.io/en/latest/faq/#faq-realtime
I don't get it. If you already have type annotations just run Pyright surely?
See for example in wdoc, my advanced personal RAG system:
https://github.com/thiswillbeyourgithub/wdoc/blob/main/wdoc/...
Re: Use Your Type System
#284Hard not to agree with the general idea. But also hard to ignore all of the terrible experiences I've had with systems where everything was a unique type. In general, I think this largely falls when you have code that wants to just move bytes around intermixed with code that wants to do some fairly domain specific calculations. I don't have a better way of phrasing that, at the moment. :(
Maybe I know what you mean. There are cases where you have the data in hand but now you have to look for how to create or instantiate the types before you can do anything with it, and it can feel like a scavenger hunt in the docs unless there's a cookbook/cheatsheet section. One example is where you might have to use createVector(x, y, z): Vector when you already have { x, y, z }. And only then can you createFace(ver…
Re: Use Your Type System
#285Shoutout to the absolutely awesome beartype for python. With simple decorators it adds runtime type checking with virtually no performance cost!! https://beartype.readthedocs.io/en/latest/ Or see their page about performance: https://beartype.readthedocs.io/en/latest/faq/#faq-realtime
you never got a TypeError before? Python already has runtime type checking
See for example in wdoc, my advanced personal RAG library:
https://github.com/thiswillbeyourgithub/wdoc/blob/main/wdoc/...
Re: Use Your Type System
#286Hard not to agree with the general idea. But also hard to ignore all of the terrible experiences I've had with systems where everything was a unique type. In general, I think this largely falls when you have code that wants to just move bytes around intermixed with code that wants to do some fairly domain specific calculations. I don't have a better way of phrasing that, at the moment. :(
Using the right architecture, you could make it so your core domain type and logic uses the strictly typed aliases, and so that a library that doesn't care about domain specific stuff converts them to their higher (lower?) type and works with that. Clean architecture style.
Unfortunately, that involves a lot of conversion code.
Re: Use Your Type System
#287The 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
#288Does 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.
It's taking the original idea behind Hungarian notation (now called "Apps Hungarian notation" to distinguish from "Systems Hungarian notation" which uses datatype) and moving it into the type system. To keep building on history, I'd suggest Hungarian types.
Meta-programming also introduced a notation which was the precursor to Hungarian Notation (page 44,45), so painted types technically pre-date Hungarian Notation.
https://web.archive.org/web/20170313211616/http://www.parc.c...
Relevant quote:
> These examples show that the idea of types is independent of how the objects belonging to the type are represented. All scalar quantities appearing above - column numbers, indices and so forth, could be represented as integers, yet the set of operations defined for them, and therefore their types, are different. We shall denote the assignment of objects to types, independent of their representations, by the term painting. When an object is painted, it acquires a distinguishing mark (or color) without changing its underlying representation. A painted type is a class of values from an underlying type, collectively painted a unique color. Operations on the underlying type are available for use on painted types as the operations are actually performed on the underlying representation; however, some operations may not make sense within the semantics of the painted type or may not be needed. The purpose of painting a type is to symbolize the association of the values belonging to the type with a certain set of operations and the abstract objects represented by them.
Re: Use Your Type System
#289Type 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…
It's literally the opposite. A string is just a bag of bytes you know nothing about. An AccountID is probably... wait for it... an ID of an Account. If you have the need to actually know the underlying representation you are free to check the definition of the type, but you shouldn't need to know that in 99% of contexts you'll want to use an AccountID in.
> Now I need to know what those are (and how to make them, etc. as well) to use your software.
You need to know what all the types are no matter what. It's just easier when they're named something specific instead of "a bag of bytes".
> https://grugbrain.dev/#grug-on-type-systems
Linking to that masterpiece is borderline insulting. Such a basic and easy to understand usage of the type system is precisely what the grug brain would advocate for.
Re: Use Your Type System
#290I 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…
The danger of that is of course that you provide a ladder over the wall you just built and instead of
temperature_in_f = temperature_in_c.to_fahrenheit()
They now go the shortcut route via numeric representation and may forget the conversion factor. In that case I'd argue it is best to always represent temperature as one unit (Kelvin or Celsius, depending on the math you need to do with it) and then just add a .display(Unit:: Fahrenheit) method that returns a string. If you really want to convert to TemperatureF for a calculation you would have to use a dedicated method that converts from one type to another.The unit thing is of course an example, for this finished libraries like pythons pint (https://pint.readthedocs.io/en/stable/) exist.
One thing to consider as well is that you can mix up absolute values ("it is 28°C outside") and temperature deltas ("this is 2°C warmer than the last measurement"). If you're controlling high energy heaters mixing those up can ruin your day, which is why you could use different types for absolutes and deltas (or a flag within one type). Datetime libraries often do that as well (in python for example you have datetime for absolute and timedelta for relative time)