Live data from Hacker News

Things I Was Wrong About: Types

v5.chriskrycho.com

111–120 of 468 posts

Re: Things I Was Wrong About: Types

#111

I don't really see most of my code being improved that much by types and I also see a lot of extra complexity that people in the sphere I am (indie games) have to deal with when using typed languages. It just doesn't seem worth it. When you have to spend a lot of time fighting your language, and handling numerous extra concepts that don't exist in an untyped language because they don't need to, it feels like the peop…

Statically typed languages (or at least the good ones) are disciplined so the programmer doesn't have to. If you can work reliably with dynamic typing, that means you are very disciplined about giving the right data to the right function, in exactly the right form. That you are very disciplined about tests, possibly including fairly stupid-looking unit tests (which aren't actually stupid, at least in a dynamic contex…

> I found that static typing actually speeds up my development. It's less work, not more.

It's a point that comes back often, and that I totally agree with so it's worth reiterating. In addition to the improved dev tooling (autocompletion, hinting, refactoring), being able to write large swathes of code without actually running it and being 100% confident that it's all _valid_ (not bug-free of course) just takes a huge load off my mind.

Of course, there's huge differences between languages like Java and languages like Typescript. Talking about "typed languages" as a homogenous concept often doesn't make a lot of sense

Re: Things I Was Wrong About: Types

#112

I don't really see most of my code being improved that much by types and I also see a lot of extra complexity that people in the sphere I am (indie games) have to deal with when using typed languages. It just doesn't seem worth it. When you have to spend a lot of time fighting your language, and handling numerous extra concepts that don't exist in an untyped language because they don't need to, it feels like the peop…

Maybe it's a case of problem complexity. I think of types as a tool to help cope with certain things. If you're building a garden wall you probably don't need CAD. For a 747, you probably do. Though aircraft predate CAD so it's clearly not impossible to do without. I dislike types in 30 lines of python because they're unnecessary complexity. I like them in 10000 lines of c++ because they do some of the thinking on my…

> I dislike types in 30 lines of python They are already there you just don't want to acknowledge them. You can build the same prototype in strictly typed language just by sticking to some primitive types like int/string and type inference, and the progress toward something more complex as your prototype grows. I personally prefer to use types right away, so type system can guide me further and show me when I'm assuming something in a wrong way.

Re: Things I Was Wrong About: Types

#113
post #19

I once told a JavaScript guru colleague of mine that I was spending my free time dabbling in Haskell. His response was 'lol, why would you do that?'. His point was that spending time learning things that you're not going to be using directly any time soon is a waste of time. My point was (and still is), that learning such things opens up a completely new way of thinking about problems and potential solutions.

Limiting what you learn is, by definition, self-limiting.

On the one hand, that's a useless truism - we can't learn everything, so you do have to pick and choose. On the other hand, I still find the framing useful, because it reminds me that, in a sense, the decisions about what not to learn are more impactful.

To the example of programming languages: Only focusing on perfecting my skills at the tools I currently use would leave me less able to understand the limitations of the tools I currently use. And would limit my ability to take my career in new paths where I might have a need to use other tools. On the other hand, learning every single new thing might distract me from properly mastering my current tools, or might eat up so much of my free time that I'm effectively spending all my time thinking about work and never recharging my batteries.

Re: Things I Was Wrong About: Types

#114
post #98

Earlier quoted context omitted.

Dynamic languages don't do away with such types, especially uint/float, etc. They just hide it away from you. The only thing it gives you is false confidence, where one day you end up doing operations on two floats because your untyped function is supposed to get numbers in, and you're left with 36.99999999999994$ on your bank account because it wasn't explicit. So, you write unit tests to make sure that you only pas…

I'm not following your answer to 2, do you have an example?

Say you'd like to have a foo method that returns... a number, whatever.

You do not need to have multiple symbols "fooString", "fooDecimal", "fooString", etc. Simply overloading the parameters gives you type safety, and keeps a single foo symbol.

    fun foo(value: String): Int = value.length()
    fun foo(value: Int) = value
    fun foo(value: RemoteDatabase) = value.servers.map { it.connect().executeSql("SELECT 1")[0].toInt() }.sum()
All these define a foo method, that returns an Int. The untyped alternative (what javascript, python, etc do in a naive way, without trying to duck type) is to do this:

    fun foo(value: Any) = when (value) {
        is Int -> value
        is String -> value.length()
        is RemoteDatabase -> value.servers.map { ... }.sum()
        else -> error("Welp, our type system couldn't help us there.")
    }

Additionally, if it really makes sense, you can define foo as an extension function on the type:

    fun Int.foo() = this
    fun String.foo() = length()
    fun RemoteDatabase.foo() = servers.map { ... }.sum()
You can then use it directly on the type, rather than call foo(1):

   val fooResult = 1.foo()
   val fooStringResult = "Well hello there".foo()

Re: Things I Was Wrong About: Types

#115

Earlier quoted context omitted.

What are you working on though? What algorithmic structure?

Compare this: private static function request(?string $method, ?string $url, array $options): array { ... } To this: function request($method, $url, $options) { ... } I can grasp the latter much better. It immediately forms a structure in my head that I will remember while I read other parts of the code. To do the same with the former, I think my brain uses up twice the energy or more. And even then, I will not have…

A better example for a typed function would be something like:

    function Request(string method, string url, RequestOptions options) : Result {...}
or

    Result Request(string method, string url, RequestOptions options) {...}

Here, we know `url` is a string (rather than the parsed object), we know all the supported options (they're members of the RequestOptions object/enum), and every value in the return value. Some might suggest even making `method` an enumeration.

If the function name was better, you could call that function right now without needing any more information.

Also, especially if you're a fan of defensive programming, most of the basic argument checking is performed at compile time, leaving the function body cleaner.

Based on your example alone, perhaps you don't have enough experience with typed languages to appreciate the benefits. I don't mean that in a belittling way, but more of an invitation to learn more about the craft.

Re: Things I Was Wrong About: Types

#116

Earlier quoted context omitted.

Counter point: with the former, I know exactly how to use it: for item in request(“get”, “google.com”, []) { .... } Whereas if there’s no example for the latter, I’d have to read the code of that function (or sometime the code of the functions it called) to know how to use correctly.

Wishful thinking. You know it returns an array, but you don't know what the array contains. So you don't know how to use it. You still need to look into the code to see what it returns. Then you will see that it returns an array and what the array contains. And now you had to process the information that it returns an array twice. Once in the function definition and once in the function body.

Most type systems also provide information about what’s in the array, like Array or int[]

Re: Things I Was Wrong About: Types

#117

For my use cases, the vast majority of errors with dynamic languages boil down to being able to run scripts that have undefined variables; I'm prone to (mental) typos, so if I had a dialect of Python that failed before runtime when undeclared references exist, I could probably cut the number of iterations I need to arrive at a working script by at least half. I've never found a valid use case for allowing undefined r…

Pycharm warns you when that happens. I'm guessing they are using a combination of the abc module (to parse the abstract syntax tree) and some linter that can be found on pypi. Would a validator that runs before your main python executable solve your problem?

Oops I meant the ast module, not the abc module

Re: Things I Was Wrong About: Types

#118
A lot of people in the comments are saying how they started off in Java, or C, and hated types, but eventually grew to love them.

I started off in PHP. It was wild. Anything could be anything. Refactoring was a nightmare. Our codebase was littered with mystery variables like $hold, $hold1, and $holda, which were re-used all over the place. (Granted, this two other problems entirely orthogonal to types.)

Then I got a job at a Java place. My god, it was beautiful. I could suddenly know what arguments functions were expecting, even if I hadn't seen them before. I could be instantly aware if I was trying to use the wrong variable somewhere, or pass in invalid data.

It was as if someone lifted me out of a dank cellar where I had previously subsisted on whatever mushrooms the rats didn't deign to eat, into a brightly lit dining room full of steak and pastries.

Re: Things I Was Wrong About: Types

#119
post #71

Earlier quoted context omitted.

>2. When you want to implement a method which applies to multiple libraries, you end up writing `fooString`, `fooInteger`, `fooDatetime` etc. DRYing is too hard. So you end up writing 10x more methods As discussed in the article, you want a sum type here. >3. No you don't avoid `null` checks at all. Entirely language dependent. >4. Generalizations are harder to implement. For some definition of harder. Harder to impl…

How many languages have true sum or union types though? For example, in Haskell I can’t declare a function as (foo: (String | Int) -> Int) and then call (foo “bar”) or (foo 123), I need to create some kind of wrapper type (like Either) to contain the possibility of a String or Int. If this were possible, there would not be such a proliferation of useless types throughout code, and code could be updated incrementally…

I agree with my sibling comment regarding Haskell, but your example essentially as written is possible in typescript. Python’s type system also allows it via the Union type, e.g. Union[str, int]

Re: Things I Was Wrong About: Types

#120
post #3

I followed a similar trajectory. Types were the bane of my early career. Hideous, extraneous. But really, they're the light at the end of the tunnel once you've worked your way though the dynamic / weak typing minefield. It took me a lot of Python, Javascript, and Ruby for me to get there, but now I'm way more comfortable on the other side. The correct type system is actually way more expressive than not having stron…

Same here! I've started with C++ and Java, learned to hate excessive typing, went through a long period of dynamic typing, and now I'm at the point you and the the author are. I still code a lot of Common Lisp on the side, but my Lisp code now looks entirely different than it looked just 3 years ago. The language standard does support optional typing declarations, and there's an implementation (SBCL) that makes use o…

My experience with strong types is limited-- I'd done the thing of learning some C, doing professional stuff in Ruby for several years and then discovering the ridiculous power strong types can have and doing some professional stuff in Go.

Typed Racket [1] was really a revelation to me in that regard. I'd be curious how developers with more strongly-typed language experience feel about it.

[1] https://docs.racket-lang.org/ts-reference/index.html

Post reply on HN