CInches in1, in2, in3; // basically just floating points
CCm cm1; // basically just floating points
in1 = in2 + in3; // no compilation error
in1 = in2 + cm1; // compilation error
in1 = in2 * in3; // compilation error
in1 = 2. * in2; // no compilation error
float foo(CInches *);
foo(cm1); // compilation error
Obviously there's a lot of code behind "CInches", but it catches so many errors.
Which other languages also support this?The type system is a programmer's best friend
281–290 of 467 posts
Re: The type system is a programmer's best friend
#282Earlier quoted context omitted.
> since the shared libs have generics and I'm always casting things. This indicates to me that you're trying to write code that isn't correct (not doesn't work , but rather only works because of implicit couplings between components) and/or doing exotic lisp-style metaprogramming. In the latter case, yeah, C#'s type system isn't powerful enough. Others are (to an extent: arbitrary code execution at compile time is ne…
Casting is often necessary for parsing inbound data from certain mysql libraries or CSV or JSON depending on how it's written. I would guess that might be what the parent is talking about. That said, if you don't cast or parseFloat or whatever in JS you're going to have a lot of trouble. And if you're doing that, why not do it in Typescript where you'll know that the data you're accessing has been safely cast based o…
No, that's what sum types are for.
Re: The type system is a programmer's best friend
#283Earlier quoted context omitted.
Vim: I can do that too, I swear! Just configure some plugins, can’t tell you what they might be though. But I’m turing complete, and I’m the best! VScode: Of course I can do autocomplete bud. Here, search my package repo, I’ll tell you which plug-ins are the most popular and handle the entire download and install process for you. There’s no comparison.
Why do you even reply to a post that you didn't bother to read? VScode is a neovim frontend. >There’s no comparison. Read the first line of my post. There literally is no comparison, because there is a category error.
Re: The type system is a programmer's best friend
#284> I want that data type to have helpful methods such as .Domain() or .NonAliasValue() which would return gmail.com and foo@gmail.com respectively for an input of foo+bar@gmail.com. No the hell you don't. Please please please do not attempt to separate the alias from an email address I submit. It's there for a reason - specifically, to hold you accountable if I experience a sudden influx of spam, and generally to keep…
This ensures everything before the @ is opaque, i.e. foo+bar@gmail.com is now bar@foo.com
Services that block my domain are usually the ones that also block foo+bar@gmail.com
Re: The type system is a programmer's best friend
#285Earlier quoted context omitted.
But there's a paradox. Why does 100,000 lines of code of python tend to be safer and more manageable then 100,000 lines of C++ despite the fact that python has no type checker and C++ has a relatively advanced type checker? Why do startups choose a python web stack over a C++ web stack? I don't think it's "self-evident." I think there's something more nuanced going on here. Hear me out. I think type systems are GREAT…
> If you have errors in your program, does it matter that much if those errors are caught during runtime or compile time? Of course it matters. If an error can be caught by the compiler, it will never get to production. Big win. With typeless languages like python the code will get to production unless you have 100% perfect test coverage (corollary: nobody has 100% perfect test coverage) and then some unexpected mome…
Something like c++. You get a runtime errors. You have no idea where it lives or what caused it.
Your python code base delivers an error but a patch should trivial because python tells you what happened. Over time these errors should become much less.
Re: The type system is a programmer's best friend
#286Earlier quoted context omitted.
It's weird to me how scanning the comments all seem to refer to systems with 100k-ish LoC and dozens of contributors. A big chunk of my job is writing node microservices in AWS Lambda. I do everything I can to avoid shared library code, since past experience tells me there be lots of dragons (mainly in when and how to push or pull lib updates to components). I have a very tiny shared lib that I try to never touch and…
> Unit tests are a breeze since I never have to cast objects or worry about generics Generics reduce the amount of things you must care about on your tests. And you shouldn't cast objects in almost no code ever. Most 100k LoC programs won't need it even once, your microservices should need it proportionally less. That's the thing. The gains grow superlineraly with the amount of code. They make it just a bit easier to…
- Define all app state as a snapshot. Problem: snapshot can become stale, so more infra might be necessary to make sure that snapshot is up to date;
- Pass only the necessary state and construct as necessary. Problem: hard to define whole state precisely and ensure that it conforms to runtime state of a healthy app;
- Pass a subset of necessary state for some execution branch and cast the type. Problem: casting may result in test failures during runtime and potentially other issues such as modify-run-fail debug loop;
- Mock return values of functions called within the function being tested and use any combination of "state passing options above".
In a lot of places I use such approach with custom type helpers and transitive types, and passing in only the necessary subset for smaller functions or mocking return values for bigger ones. What do you think? I know that the AppState can be defined as a union of possible states and together with type guards can address those issues better. I just wanted to hear your opinion on how you would address such problems. I hope I explained it well enough.
export type Fn = (...params: any) => any;
type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
export type FirstParamType = G extends Fn[]
? UnionToIntersection[0]>
: G extends Fn
? Parameters[0]
: never;
export interface AppState {
first: {
a: number;
b: number[];
};
second: {
c: string;
d: string[];
}
}
type DeepPick = { [BK in B]: Pick };
function calculateUsingFirstB(state: DeepPick): number[] {
return state.first.b; // some calculation
}
function calculateUsingSecondC(state: DeepPick): string {
return state.second.c; // another calculation
}
// function which takes complex state parameter and calculates the result based on results of other functions
function calculateMore(state: FirstParamType & DeepPick): string | number[] {
if (state.first.a > 10) {
return calculateUsingFirstB(state);
}
return calculateUsingSecondC(state);
}Re: The type system is a programmer's best friend
#287Articles like this bug me. You've given me a list of why types are awesome. Great. Now, tell me what the tradeoff is. Nothing is free in engineering. To get something, you have to give up something else. Even grug[0] understands this. [0]: https://grugbrain.dev/#grug-on-type-systems
For a while in the codebase I was working on, we had a set of distinct types for different units. You know, a type for meters, another for centimetres, etc etc. We had types for radians, types for degrees. We had conversion functions between them, and type inference when you performed certain operations. The result was a disaster. Not an enormous disaster, but enough of a problem to rip the entire thing out and repla…
wtf? metres and centimetres are not different types! they are just different ways of writing same type: Length. radians and degrees are just ways of writing a dimensionless Angle quantity. you made the absolutely elementary mistake of conflating a physical quantity with the unit used to measure it, of course it was a disaster.
>nothing sensible to infer when you, say, multiply an angle and a distance
angles are dimensionless so they should just be a distinct type of float. there is literally no problem here.
Re: The type system is a programmer's best friend
#288This is, IMvHO, such old news that it feels... weird to still read about it in a year with the prefix of 20. Every programmer who has ever single-handedly written a 100,000+ LOC software system will tell you the same thing: shift as much responsibility on the compiler as you can and have the compiler check the code you write to any extent technologically possible. Getting rid of bugs by experiencing, diagnosing and f…
But there's a paradox. Why does 100,000 lines of code of python tend to be safer and more manageable then 100,000 lines of C++ despite the fact that python has no type checker and C++ has a relatively advanced type checker? Why do startups choose a python web stack over a C++ web stack? I don't think it's "self-evident." I think there's something more nuanced going on here. Hear me out. I think type systems are GREAT…
Because C++ sucks, but static types are not to blame for that.
Re: The type system is a programmer's best friend
#289I have to plug Ada's rich type system for explicitly encouraging this kind of design. With things like type predicates [1], you can do run-time enforcement or even prove at compile-time (to optimize away the runtime checks) that type constraints are met. As an example of this, in a piece of code I'm working on there's a Base64_String type, where only RFC 4648 characters are permitted to be part of the string, the '='…
Not just that, but it also often does so efficiently and doesn't incur a runtime penalty (for new type and static predicates) and will reuse previous function definitions as well. These are the sorts of cases with function parameters in various languages other language I've dealt with, in which this would have helped: - "dt": delta time of what? Seconds, milliseconds, microseconds, nanoseconds, ticks? Usually, I'd ex…
Rust having builtin IP address types (and libraries actually using them) is long overdue for mainstream programming languages
Re: The type system is a programmer's best friend
#290I'm learning Python after 35 years of working with statically typed languages (Pascal, C++, Java, a bit of Typescript lately) and by god this is hard. Not because there is anything in the language that I don't understand but the lack of any type info is killing me. I just can't build up a rhythm of coding. I feel like every five lines I have to sprinkle in print() statements to keep track of the data transformations…