6 ms·
List typing isn't as superficial as it seems. The following has happened to me multiple times, perhaps in the last month: I have a large code base. I want to r
by danharaj 9y ago
List typing isn't as superficial as it seems. The following has happened to me multiple times, perhaps in the last month:
I have a large code base. I want to replace a fundamental data structure to support more operations/invariants/performance guarantees. I change the type at the roots of the code base. My instance of ghcid notifies me of the first type error. I fix it. This repeats until the program compiles again. I run the tests. All the tests pass.
This is insane in Python/C/Ruby. I've had to do it in C and Python. In Haskell I do it with impunity.
The type system doesn't just check what my program does, it is the compass, map, and hiking gear that gets me through the wilderness.
- DubiousPusher 9y agoYup, love that about statically typed languages. This happens all the time for me in C#. I have several libraries I like that do a lot of code generation. When the project is young, directly handling the generated classes works well but as the project grows, I inevitably want to wrap the handling of the generated classes. It's awesome to be like, welp... it's time to handle this one type differently. Change the return type of an interface or the type of a container and just have the compiler tell you everything you broke.
- underwater 9y agoI’d argue that code generation is an anti—pattern that is only necessary because of static typing. A dynamic language would let you change the implementation of all generated objects simultaneously.
- dragonwriter 9y agoIn principle, this should be possible with static typing with a robust enough type system, too.
- yorwba 9y agoCode generation by macros is an important feature of Lisps, which tend to be dynamically typed. Maybe it feels less like code generation when you don't also have to produce the correct type annotations, but a good inference engine can eliminate most of those from statically typed languages as well.
- subwayclub 9y agoCode generation is, in essence, the ultimate static construct since it allows you to compile any feature you would achieve through late binding and reflection, but with a static code path. Which in turn lets you leverage the compiler toolchain more and bring more errors towards compile time(where they're cheap to resolve). Dynamic languages can always lean on runtime features, but that's also their peril. Late binding deprives you of leveraging the tools in favor of "trust me". In both cases you can get a maintenance nightmare, of course. The point as I see it is to move things toward the runtime when the error case is not troublesome, and towards the compiler when automating in more safeguards would help.
- throwawayjava 9y agoA lot of generated code could be done with reflection or meta-object protocols. There's a good reason people generate code instead (in statically and dynamically typed languages!): performance.
- DubiousPusher 9y agoThat may be entirely true and everything you can achieve with Roslyn and T4 templates may be achievable through some more elegant construct in another language. But I've never had the luxury of choosing a tech stack for it's purity of design. So the feature is wonderful in my day to day regardless. I'd love to build 3D experiences in a language like lisp or scheme. It'd be great fun to learn but I don't currently have the luxury of the time it would take to ramp. And I certainly don't have the political capital to convince my entire dev team to change.
- bjz_ 9y agoYou can actually do a huge amount of metaprogramming in dependent type systems and still have the the power of static checking. We're still figuring out how to improve the ergonomics to the level that it matches macros and other code-gen methods, but it's super exciting stuff.
- Sir_Cmpwn 9y agoI don't really the lumping of C in with Python and Ruby here. The C compiler picks up on that, too. All over this comment section people are calling C weakly typed, I don't get it. Is it because void* exists? Every language has something like that.
- muricula 9y agovoid * is part of it, but you can also implicitly cast from between integer types, and also between integers and enums. Think of passing an enum or an int into a function which takes a long as an argument.
- Sir_Cmpwn 9y agoI mean... I don't really think that's a strong case for calling C's type system weak.
- bitwalker 9y agoI suspect most people which state that C has a weak type system are really talking about the fact that C has a weakly _enforced_ type system. You can break the type system's rules rather easily (or perhaps it's more accurate to say, the type system is too permissive), either way it doesn't provide you the same guarantees a stronger type system provides). At least that's my take on it.
- fulafel 9y agoThis.
- alloyed 9y agoI would say it's mostly a matter of use: In C you deal with void* or typecasts all the time, whereas in higher level languages it's much less common, either because the type system is smarter, or the constraints that it does have are more strictly enforced. For example: you can happily compare a char* and an int in C, but other languages like python might error at the thought.
- fabioz 9y agoI find that people doing these claims have seldomly really worked in large Python codebases... Personally, I find it pretty workable in Python with a big codebase (but you have to respect the rules like having a good test suite -- you change the time from compiling to running your test suite -- which you should have anyways)... I find that the current Python codebase I'm working on (which has 15 years and around 15k modules -- started back in Python 2.4, currently in Python 2.7 and going to 3.5) pretty good to work in -- there's a whole class of refactoring that you do on typed languages to satisfy the compiler that you don't even need to care about in the Python world (I also work on a reasonably big Java source codebase and refactorings are needed much more because of that). I must say I'm usually happier on the Python realm, although, we do use some patterns for types such as the adapter protocol quite a bit (so, you ask for a type and expect to get it regardless of needing a compiler to tell you it's correct and I remember very few cases of errors related to having a wrong type -- I definitely had much more null pointer exceptions on java than typing errors on Python) and we do have some utilities to specify an interface and check that another class implements all the needed methods (so, you can do light type checking on Python without a full static checking language and I don't really miss a compiler for doing that type checking...). I do think about things such immutability, etc, but feel like the 'we're all responsible grown ups' stance of Python easier to work with... i.e.: if I prefix something with '_' you should not access it, the compiler doesn't have to scream that it's private and I don't need to clutter my code -- you do need good/responsible developers though (I see that as an advantage).
- orclev 9y ago> I definitely had much more null pointer exceptions on java than typing errors on Python Null pointers are a type error. The fact that several nominally "statically" typed languages don't differentiate between nullable and non-nullable types is a significant source of failure in their type systems. Using a modern language that properly identifies nullable values as a distinct type from non-nullable ones goes a long way towards eliminating a whole host of problems. It will be interesting to see what things look like in 10 years or so once Rust has had time to really displace a significant portion of the C and C++ code in the wild, and hopefully Kotlin has killed off Java (and if we're really lucky Typescript has done the same more or less with Javascript).
- jonnytran 9y agoI do the exact same thing on large codebases of Ruby, but instead of the compiler type-checking errors, it's the test suite errors. It's true that static type-checking proves the absence of an entire class of errors. But it doesn't prove that the code does the correct thing; it could be well-typed but completely wrong. On the other hand, tests prove that the code does the correct thing in certain cases. ...Of course, it's up to the developers to actually write a good test suite. The faster we can all accept that there are pros and cons to both, the faster we can come up with a solution that takes advantage of the best of both worlds. That's the whole point of this OP. I, personally, have always wondered about ways to dial in to the sweet-spot over time as a project matures. At the start of a project, shipping new features faster is often more important. But if the project survives, maintenance (by new developers) and backward compatibility become more and more of a priority.
- catnaroek 9y ago> It's true that static type-checking proves the absence of an entire class of errors. But it doesn't prove that the code does the correct thing; So prove it yourself. Proving things about programs that rely on dynamism is invariably much harder than proving things about programs that don't.
- erfgh 9y ago> This is insane in Python/C/Ruby. It's only insane if you don't have test cases with good coverage, in which case you are very-very-very screwed, statically typed or not.
- rndmio 9y agoTesting is not the answer to the problem of knowing if I refactored everywhere necessary. In a statically typed language I don't even have to worry about what do I do if my function is passed a var of the wrong type, it won't compile.