Hacker News new | ask | show | jobs
by tomc1985 2618 days ago
So, what, everyone standardizes around an IDE then? You really think that's gonna unite the vim and emacs camps?

I'm personally tired of staring at variables trying to figure out what they're supposed to be, then having to dive into source to see how its used. C/C++/C# solved that problem, why are we still dealing with it?

3 comments

C had some typing, but I'm not going to call it "solved" until "numberOfHats = distanceInPixels + weightInKg" is considered a compile-time error due to the three "int" values being incompatible; but "numberOfHats = aliceHatCount + bobHatCount" is acceptable.

How does nobody(?) support this yet?

Python supports some parts: you can subclass int, and you get all of the int methods like addition and subtraction for free, but "distanceInKm + distanceInKm" gives you an int instead of a distanceInKm; and "distanceInKm + distanceInMiles" gives you an int instead of an error.

Rust also has partial support but from the other end: distanceInMiles and distanceInKm can be two distinct subclasses of int, and adding them together is a compile time error. But also adding distanceInMiles with distanceInMiles is a compiler error, because these are basically "completely new classes" rather than "subclasses of int", and so you have to implement add / subtract / stringify / etc for yourself for every type D: (I'm fairly new to Rust so if there is a shortcut there that I'm missing please do point it out)

Every language that has generics supports this via phantom type variables that can encode extra information only in the type system alongside some other type, or with a specific newtype keyword that effectively does the same:

    newtype Pixel = Pixel Int
    newtype Em = Em Int

    pixelWidthToEm :: Pixel -> Em
    pixelWidthToEm (Pixel px) = Em px
You can try to call `pixelWidthToEm` with anything other than pixels and it won't work.

More dynamically, with an open type variable that only exists in the type system:

    data User a =
      User { name :: String, socialSecurityNumber :: String }

    data LogSafe
    data LogUnsafe

    logUser :: User LogSafe -> IO ()
    logUser = undefined

    makeUserLogSafe :: User LogUnsafe -> User LogSafe
    makeUserLogSafe = undefined
We can never log the user unless the user is deemed LogSafe and we make functions that produce log safe users that you have to call before hand, in order to make sure that sensitive data isn't printed to logs.

These are things that have been around for a long time in almost every type system, but people's general lack of interest in using type systems to help them conspires to keep them in the dark.

Here's how you can create a number type distinct from other number types in TypeScript:

    type DistanceInPixels = number & { readonly __newtype__: "DistanceInPixels" }
And a type alias that allows you to create them:

    export type Newtype<T, Tag extends string> = T & { readonly __newtype__: Tag }
    type Pixels = Newtype<number, "Pixels">
I get similar concerns with functions that take multiple strings - how do I make sure I didn't swap the bucket with the key? I've seen enums used here, as well as "wrapper" classes.

In any case, to answer the question of "How does nobody(?) support this yet?", have you heard of https://frinklang.org/ ? It's not a useful tool for most codebases I work on but it's an interesting idea.

You could do this in C++ by storing the unit of measure with the measurement value and then performing unit conversion in overloaded math operators.
(They won’t be subclasses in Rust, Rust doesn’t have classes nor inheritance. They’d be “newtypes”, a struct with one member.)
Do they, the language is called F#.
It rarely happens to me that I stare at a variable and have to wonder what type it is. And yes, an IDE like Rubymine is becoming crazy good at autocomplete and method lookup. I think the experience of developing on Rubymine isn't that far behind from Intellij nowadays. Not everyone have to use the same IDE, the vim or emacs guys will have to find equivalent tools.
Algol solved the problem.