Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Like others have said, dynamically typed languages still require you to think about the types, except that now you don't have the automatic hints the IDE can provide you, the guarantee of safety once your code compiles etc.

Typed codebases are far better to return to than untyped ones. Anyone who doesn't think so has probably not tried a good, typed language with a good IDE.



It is interesting that so many people believe, and strongly enough to downvote, that you must think about types when programming. A claim that people can't program unless they are thinking about types.

I have provided examples in other comments where types is about as far away from my mind when writing complex programs. In terms of guarantee of safety, system and integration tests do that. Types are not based on customer requirements, nor do they verify that the program do what I get paid to do. A type is simply a limited set of automatic restrictions and tests to very that those restrictions are followed.


Because the claim "you're not thinking about types" is absurd. You can't pass a LoggedInUser to a thing expecting a URL. You can't pass a AccountIterator to a thing expecting a UUID. You can't pass a function closure to a thing expecting a string. And so on.

You have to be thinking about types, because the computer can't. Since your programs work (I assume), and computers can't be doing this for you, by process of elimination, you're the one thinking about types.

What is actually happening is either that you've so deeply internalized it you don't realize it any more than you think about individual muscle contractions while walking, or you don't recognize what "thinking about types" means. For instance, I imagine an obvious riposte to my first paragraph would be "But if the code expects a URL and I pass it an LoggedInUser, I can set it up so the LoggedInUser can yield or function as a URL", which is in fact precisely "thinking about types" because you just changed the type of your LoggedInUser.

(You want to see someone who is truly "not thinking about types", go help someone learn programming for the first time, who truly innocently tries to pass a User to something expecting a URL and is truly surprised when that doesn't work because they truly, deeply thought the program would just figure out how to turn that into some URL they had in their head for the user, but never explained to the code. That's "not thinking about types". It is nonfunctional.)

As others have said, dynamic code requires you to do more thinking about types, not less, for two reasons: One, the compiler isn't doing it for you, and two, you have a lot more things to juggle in a dynamic language than in most static ones precisely because they give you more power. You shouldn't be fighting this idea, you should be embracing it; it is precisely the fact that they make you think more about types and leave more of the decisions to you that gives you the additional power in dynamic types you are enjoying.

But that additional power irreducibly comes with more responsibility. You can't claim you've obtained the power yet somehow dodged the responsibility of managing it. You are holding a lot more state in your head that has no existence in your source code than you would be in an equivalent static program. You can't claim you've got that state in your head but you're somehow not "thinking" about it.

You're thinking about types all the time. Your complaint is more than you like a programming style that involves very complicated type ideas that are difficult to express in a static language. (Or, possibly, that you haven't taken the time to learn to express in a static language. There are some static languages that work better with this style than others.) Or that you don't want the constraint of having to express them. So you stick to an environment that loads the work on to you instead in return for the power of those more complicated things you never have to lay out for the compiler. But the work is getting done somewhere. It has to be, or your program wouldn't work.


@belorn:

> You can pass a LoggedInUser to a thing expecting a URL in a dynamic language if the LoggedInUser has the same methods as defined in the interface of an URL. It called ducktyping. In the same line of thought, you should even actively avoid checking if LoggedInUser is of the type URL because a different type sharing the same interface as URL should be equally accepted as URL.

You can do that in statically typed languages as well (though not in every). See C++. Rust actively decided against it, and makes it the users responsibility to say "yes I indeed want to give this type to this function, because it satisfies the trait like this".

Is a type, as defined above, required for all programming? No. Interfaces? Yes. Interfaces are also more similar to customer requirements in that they define behavior. Do the object has an absolute path method. Do it has an UUID property. Can it be used to call open on. Those questions are not type questions, and so I do not think about type when answering them.

Interfaces in TypeScript just describe sets of types, so yes you are still thinking about types (about types of types). I'd like to know why you think either one is (syntactically) required for programming (as we know ASM doesn't have either of those) Further, I'd like to know how you don't think about basic types in JS. Finally, I'd like to know why you couldn't fall back to (mostly) duck typing in statically typed langauges.


> I'd like to know why you think either one is (syntactically) required for programming

Taking the concept of interface, it would be difficult to program something with objects if you did not know the methods, properties, events. Just knowing the type name without any of the knowledge about the interface of the object would make programming close to impossible. The opposite however, knowing the methods and properties but not the type, is enough information to write a program.

In one python program I wrote I created a proxy object for a third-party library. The library only supported a single process, and I needed multiprocessing. The proxy object allowed me to take every call to the object from process B to be pickled and forwarded to process A, with the return value being sent back to B. No function needed to be made aware of the proxy object, the third-party library behaved just as it was a single process program and everything just worked. The proxy object did not need to have any information about the call signatures or method names of the third-party library objects.

It would be interesting to see such proxy object being written in a statically typed language that maintain the type checks when the proxy object get used inside a third-party library. Requirements would be that the proxy object should be independent implemented without being effect by the call signatures and method names in the third-party library. It sounds a bit fun trying to get the compiler to resolve what the type and signature should exist at compile time, through that might just be implementing a dynamic-like language through macros and compiler tricks.


What you'd end up doing is copying and pasting a lot of code. You'd need to define one kind of proxy object for one type in the third-party library, and another kind for another type, and so on. Each would need to implement all the methods, with correct type signatures.

Perhaps you could parse the source code to the third-party library and generate matching proxy objects from that.

No number of compiler tricks would allow you to define a single object that can be a proxy for anything using a statically-typed language.


Exceptional comment, thank you.


You can pass a LoggedInUser to a thing expecting a URL in a dynamic language if the LoggedInUser has the same methods as defined in the interface of an URL. It called ducktyping. In the same line of thought, you should even actively avoid checking if LoggedInUser is of the type URL because a different type sharing the same interface as URL should be equally accepted as URL. Two objects with the same interface should not be treated different unless very special circumstances.

If the code only expect the interface of an URL, the type of the object being sent in is irrelevant, and thus the programmer do not need to think about the type. Instead we are thinking about interfaces.

Programming in a dynamic language do allow a programmer to not think about types, but they do need to think about interfaces. Programming in a static language require the programmer to think about types, but they also need to think about interfaces. Having types does not eliminate the obligations to think about interfaces regardless of programming style.

If we want to use TypeScript as an example, a type is a data type of either Any Type, Built-In Type, and User-Defined Type. The Type System in TypeScript is responsible for checking the data type of any value taken before it can be provided as an input to the program.

Interface in TypeScript: An Interface in TypeScript is a syntactical obligation that all entities must follow. It can only contain the declaration of the members and is responsible for defining the properties, methods, and events. In a way, it is responsible for defining a standard structure that the derived classes will have to follow.

(above taken from https://www.geeksforgeeks.org/what-is-the-difference-between...)

Is a type, as defined above, required for all programming? No. Interfaces? Yes. Interfaces are also more similar to customer requirements in that they define behavior. Do the object has an absolute path method. Do it has an UUID property. Can it be used to call open on. Those questions are not type questions, and so I do not think about type when answering them.


> Two objects with the same interface should not be treated different unless very special circumstances.

...until you accidentally pass the ClientsTable object to the delete_supplier() function, which expects a Supplier object. Unfortunately, the delete_supplier() function calls the delete() function of the passed object, which is helpfully provided by ClientsTable. Bummer. Eh, just restore it from backups, right?


Unfortunately right before that an SQL function was called that wiped the database, just before calling the banking function that used an corrupt pointer to send a large sum of money to a random tax account which then happened to have a major tax debt, and as matter of tax law one can't demand money back from the government if paid to such account.


You've completely missed the point: A powerful static type system helps prevent many types of logic bugs.

No, it won't prevent every conceivable bug or error, but nobody claimed it does. Automatically ruling out a large class of bugs at compile-time is still very valuable. Don't let the perfect be the enemy of the good.


In almost 20 years of writing programs I have yet to write a delete function that dynamically call delete based on the object type. Having a delete_supplier() function that assumes Supplier object is a pattern that has direct security issue baked in.

The closest I would ever have gotten to the above scenario would be the time when I wrote an array of function pointers to be called in a parallel process. A bit of rather complex C code, and if I recall a bunch of void pointers.

If you intend to provide examples or bugs being caught with type checking, it would be useful if those examples actually occurred and were caught by the type checking.


You sure seem to be thinking about types a lot for somebody who claims to not have to think about types. Which is the entire point everybody is trying to make you understand.


You seems to insist on that a lot, but can't seem to show it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: