[HN Gopher] Strong static typing, a hill I'm willing to die on
___________________________________________________________________
Strong static typing, a hill I'm willing to die on
Author : tasn
Score : 321 points
Date : 2023-10-04 12:49 UTC (10 hours ago)
(HTM) web link (www.svix.com)
(TXT) w3m dump (www.svix.com)
| bspammer wrote:
| Asking someone to maintain an untyped codebase is like asking
| them to play a game without telling them any of the rules.
| globular-toast wrote:
| I agree, for an _untested_ , untyped codebase. Unit tests are
| more valuable than types IMO.
| occz wrote:
| Luckily, you don't have to trade off between them, and
| neither replaces the other.
| riskable wrote:
| Your statement reminds me of the spoon scene in The Matrix:
| Instead of trying to bend the code to fit within the confines
| of its types simply try to realize the truth... Static types
| are just _more code_. They 're extra conditions that we apply
| to things like function signatures and variable definitions
| instead of adding conditional checks where it matters.
|
| "Aha!" you say, "but by enforcing conditional checks at
| variable definition and inside function signatures we don't
| _have_ to check them ourselves in our code and the compiler
| itself can check them to ensure correctness and optimize
| performance! "
|
| ...and I'd agree with that sentiment but I'd also add that by
| having to reason about your types _constantly_ you 're adding a
| non-trivial amount of mental overhead when structuring your
| code. For some people _that 's how they reason about their code
| anyway_ but for others, having to consider whether or not a
| number is a `u8`, `u32`, or `usize` adds a _lot_ of complexity
| to the code that could very well be entirely unnecessary
| depending on the use case.
|
| Consider, for example a program that's meant to be executed on
| the command line that takes two numbers and adds them together.
| No matter what language you use you have to convert the raw
| string input into a numerical type before performing the
| addition.
|
| In Python you have a simple function, `int()` that will happily
| turn any string consisting of numbers into a proper integer
| that can be used for math operations. If it gets something that
| isn't a number it'll throw an exception which is trivially easy
| to detect and wrap in a `try`/`except` block with a user-
| friendly error message. If we wanted to support floating point
| numbers we could _just use_ `float()` and the code would
| otherwise be exactly the same.
|
| In strongly-and-statically-typed languages this same process
| involves _considerably_ more overhead. Before we can select a
| function to convert a string into a number we must first pick a
| numerical type and before we can do that we must think real
| hard about how big of a number we 're going to support in this
| application. Our function signature(s) could also get
| complicated because, "wait: what _type_ of string are we going
| to get from the command line? " Something as simple as adding
| two numbers becomes complicated really quickly!
|
| Comparing the two ways of handling things (strongly, statically
| typed VS strongly, dynamically typed), Python ends up the clear
| winner a lot of the time because you got the job done without
| having to think as much, with less code that's super easy to
| reason about _even though it didn 't use static typing_.
|
| The other problem is that when you write such trivial programs
| in strongly, statically-typed languages like C, C++, Rust, etc
| it requires a lot more mental overhead to look at the code to
| figure out what's going on/how it works (though with Rust, less
| so because there's not 1001 awful ways to do things haha).
| handsaway wrote:
| > Before we can select a function to convert a string into a
| number we must first pick a numerical type
|
| Except this has literally nothing to do with static typing
| and everything to do with whether or not the language you're
| using cares about numeric types.
|
| For instance in typescript you'd just have `number` as the
| type. You could conceive of a dynamically typed language like
| python where adding a u8 to a u32 would cause a runtime
| error. In which case it sure would be nice to have the
| compiler tell you to convert before you called a function.
|
| >The other problem is that when you write such trivial
| programs
|
| If only I had a career writing trivial programs that would
| make a lot of things easier.
| valcron1000 wrote:
| > In Python you have a simple function, `int()` that will
| happily turn any string consisting of numbers into a proper
| integer that can be used for math operations.
|
| For starters this is not the case, it does not work on a
| string of numbers: >>> int("123 890
| 123") Traceback (most recent call last):
| File "<stdin>", line 1, in <module> ValueError:
| invalid literal for int() with base 10: '123 890 123'
|
| > Before we can select a function to convert a string into a
| number we must first pick a numerical type and before we can
| do that we must think real hard about how big of a number
| we're going to support in this application
|
| Aren't you doing the exact same thing in Python by picking
| `int()` over `float()`?
|
| > what type of string are we going to get from the command
| line?
|
| Well, this might be the case for system languages, but most
| have a single `String` type.
|
| Here is the program you described in Python
| def main(): n1 = input() n2 = input()
| sum = int(n1) + int(n2) print(sum)
|
| And here it's in Haskell main = do
| n1 <- getLine n2 <- getLine let sum =
| read n1 + read n2 print sum
|
| Accepting a single line of numbers is not much different
| main = do nums <- words <$> getLine let
| res = sum $ map read nums print res
|
| I didn't think much about it, it's not a lot of code and I
| guess it's easy to reason about?
| frou_dh wrote:
| Trust the science on this.
|
| Wait, I've never looked at it. I guess that's why I used the word
| trust. Surely it confirms my preferences.
| Luctct wrote:
| Is that a promise? Are you people really going to die? How soon?
| Any chance you die by the end of this week?
| dang wrote:
| Hey, could you please review
| https://news.ycombinator.com/newsguidelines.html and use HN in
| the intended spirit? You broke that badly with this post, and
| we're trying for something else here.
| victorNicollet wrote:
| I think there are at least two ways to write safe and robust
| code, one being to rely on static types to provide automatic
| guarantees, and another being to structure the program in a way
| where tests reveal errors immediately. They are mutually
| incompatible, and so different from one another that few people
| can be experts at both, but I don't think one is objectively
| inferior to the other.
|
| Both styles require code to be disciplined, and undisciplined
| code cannot be caught by compilers, linters or automatic tools,
| it has to be through code review (or experience and sheer
| willpower). It's easy to think of examples where a lack of static
| types would allow brittle code to be written, but it's important
| to question whether that brittle code may be considered
| unacceptable by someone experienced in working without static
| types, in the same way that code using a Dictionary<string,
| object> instead of an actual type would be considered
| unacceptable by a type-safety practitioner despite being
| (technically) type-safe.
| evrimoztamur wrote:
| Why are they incompatible?
| victorNicollet wrote:
| For example, with static typing one would define many
| different complex types over the program, in order to have
| the compiler enforce the many different constraints (here the
| value can be null, but not there ; these two values must be
| provided together ; and so on). Things like structural typing
| or algebraic data types even allows the creation of unnamed
| types on the fly. When sum types are used, conditional
| operators will be used to deconstruct these in a type-safe
| way, resulting in many branches.
|
| With dynamic typing, one would have only a small number of
| very different types, because having many types increases the
| risk of using the wrong one, and having similar types makes
| it harder to notice that the wrong one is being used. The
| types must be very simple, because deconstructing complex
| types requires having branches, and branches should be kept
| to a minimum because they are hard to cover properly with
| unit tests.
| kakadu wrote:
| The embracing of Typescript and type hints pretty much solidifies
| the case against dynamic typing for complicated projects.
|
| We have projects in java7 still which span thousands of LoC and
| juniors can just jump in using their IDE and make _some_ sort of
| contribution.
|
| With python this takes much longer.
| dartos wrote:
| Is typescript strong typing though?
|
| I've been through several typescript projects where 'as unknown
| as any' makes me wish we didn't even have typescript in the
| first place.
|
| If you can't trust the type system it's worse than not having
| one :/
| agos wrote:
| if you abuse the type system enough, most languages will have
| weaker typing.
|
| "the language" is not enough per se, you have to use the
| tools it gives you to gain some advantage: those projects
| were clearly actively avoiding strong typing, for whatever
| reason
| dartos wrote:
| In js land some packages don't have strong types or, worse,
| wrong handmade types. 'as unknown as any' is kind of needed
| in those cases.
| Tade0 wrote:
| > Is typescript strong typing though?
|
| The term "strong typing" doesn't have a clear definition to
| begin with.
|
| Other terms which it often substitutes do, e.g. static
| typing, sound type system, decidable type system etc.
| master-lincoln wrote:
| apparently the words strong and weak typing have no agreed
| upon definition so they can not be meaningfully discussed
| without stating your definition.
|
| e.g.
| https://perl.plover.com/yak/12views/samples/slide045.html
| rpdillon wrote:
| Wow, that's a fairly eye-opening post! I have always used
| definition 5 for strong typing. I would love to know where
| the other definitions come from.
| ng12 wrote:
| You can write bad code in any language.
| master-lincoln wrote:
| I think this comment doesn't add to the discussion. It's
| like saying you can kill yourself in any vehicle. Might be
| true (or maybe not), but doesn't add to the discussion of
| vehicle safety.
| junon wrote:
| I'm tired of this adage. Yes, you can. Some languages make
| it _way, way easier_ to write bad code, though.
| poszlem wrote:
| This is a thought-terminating cliche and does not add
| anything to the discussion.
| jrajav wrote:
| I, too, find tools hard to use after I intentionally break
| them.
|
| It's unfortunate that Typescript even provides this casting
| hack, though it's necessary for gradual, optional typing. The
| very first thing I would do on such a project is spend the
| time to fix those broken types, because it will pay back in
| full in productivity after a short time.
| [deleted]
| chpatrick wrote:
| Python is very much heading towards static typing although it
| isn't as mature as TypeScript yet.
| wait_a_minute wrote:
| > We have projects in java7 still which span thousands of LoC
| and juniors can just jump in using their IDE and make some sort
| of contribution.
|
| This seems to be a main reason certain people like it. It gives
| a sense of productivity. However I think it is misguided. It's
| a false sense of productivity. Can they commit? Maybe, yes.
| Will it be right? Maybe, and more likely with types to
| handhold. But does it mean they understand the data model and
| the domain of the codebase they're working in? No. No typing
| forces you to know what your code is actually doing.
|
| It takes longer to be productive, but you'll be productive
| because you know what you're doing. Not because the IDE held
| your hand.
|
| Widget factories or scrum farms will no doubt like the "ease"
| of jumping into a codebase that has typing, but I'm not yet
| convinced it's better or that much better for the experience
| developer. I need to think on it more. For certain though I've
| seen enough in my time to know that how quickly a junior can
| "just jump in and make some sort of contribution" is not a good
| measurement.
| berkes wrote:
| "Truly understanding what goes on" and "static typing" are in
| no way correlated, let alone causations.
|
| You are making a false dichotomy.
|
| It's perfectly possible to work in a dynamic codebase without
| understanding the domain, business, logic or big picture. And
| it's just as perfectly possible to build a statically typed
| codebase that forces you to understand the whole entirety
| before being able to make a change.
|
| Now, whether it's actually _good_ to enforce true
| understanding of the Whole, before being able to work on a
| subset, is another debate. One that, unsurprisingly, has long
| been proven to be false. It 's why we consider modules,
| functions, boundaries, coupling, classes, microservices,
| layers, and so fort and so on.
| BigJono wrote:
| Dude, duck for cover, lol.
|
| You're 100% right though.
| marcosdumay wrote:
| Nope. A new dev will need a lot longer to understand a large
| python codebase than a java one.
|
| In fact, if all the developers change, it's a virtual
| certainty that none will ever understand the python code,
| while the odds are about even for java.
|
| (But then, the types aren't the only factor for that.)
| master-lincoln wrote:
| Your argument sounds like a language should make it hard to
| understand parts of a codebase without understanding the
| underlying parts as well. I would argue this goes against the
| goal of abstracting problems to keep complexity manageable.
|
| Of course abstractions can be misunderstood and misused, but
| is that an argument for not having them?
| germandiago wrote:
| Clojure author Rich Hickey disagrees on this. He argues that not
| only typing is what you need since many of the errors are not
| typing errors and not even most are (not sure he said that last
| thing exactly though, talking from the top of my head). The point
| being that an alternative that can check that and more is better.
| Also, he argued that types are key/values no matter the formal
| type if it is the same thing in two systems.
|
| So he created spec. Spec can check more invariants than just
| typing. Truth to be told, Clojure is functional and one of the
| goals is to generate test cases from those specs. So it is a bit
| of a different story probably.
|
| At the end we want correct software.
| waffletower wrote:
| I think there is strong religious orthodoxy surrounding static
| typing in computer science, and this article reflects this
| religiosity. Strong typing proponents often fail to acknowledge
| alternative beliefs which assert that strong typing paradigms can
| be less effective and efficient than dynamic typing for many
| software development contexts. Rich Hickey, the creator of
| Clojure, is a fairly prominent counter-voice of this debate and
| provides some interesting context in this presentation:
| https://www.youtube.com/watch?v=2V1FtfBDsLU&t=2227s
| amelius wrote:
| How long until Copilot can type-annotate any piece of dynamic
| code, making the issue mostly irrelevant? Everybody sees the code
| how they like to view it.
| doktrin wrote:
| I don't have much to say about the piece itself other than
| express broad agreeement on what is a fairly common sensical
| topic, but just gonna say it's interesting how many commenters
| here are up pontificating on their soapbox while still clearly
| confused about the distinction between strong and static typing.
| hcks wrote:
| The static typing hype bubble which started 10 years ago is soon
| going to burst.
|
| As a falloff expect decades of engineers lamenting overly
| engineered, overly verbose, overly complex TS legacy apps.
| awestroke wrote:
| I've never met anybody who prefers JS over TS.
|
| If anything, the dynamic typing bubble is bursting right now.
| meiraleal wrote:
| > I've never met anybody who prefers JS over TS.
|
| It is because the enterprise TS supporters are too loud.
|
| There are many here saying they consider people that dislike
| TS to be idiots and they don't lower themselves to discuss
| with those who think JS is preferable.
|
| They don't wanna argue, we don't wanna argue. Life is great.
| yakshaving_jgt wrote:
| I prefer JS over TS, and I'm predominantly a Haskell
| developer.
|
| But then again, I suppose we haven't met.
| panzagl wrote:
| Have you met anybody who prefers JS over Java?
| iopq wrote:
| I do, because I don't enjoy having to throw some exception
| I don't care about just because it's "checked"
| ilrwbwrkhv wrote:
| I prefer how much cleaner JS code is compared to TS. Some TS
| errors are such an eyesore that I'm reminded of the ugliness
| of Microsoft.
| BigJono wrote:
| And decades of startups created with the next
| lisp/ruby/python/perl/JS. Sign me up for those. I for one would
| rather eat a bullet than maintain any of the TS I'm watching
| people write today.
|
| I don't think we're near the peak yet. We're still on the way
| up. I've seen $5M projects turn into $50M projects in the space
| of 5 years and nobody else in my little consulting bubble has
| noticed at all lol. It shouldn't take 100 devs to build a SaaS
| with 5 forms and a dashboard but here we are...
| pron wrote:
| > Yes, typing can be a pain in languages that don't support
| inference, e.g Java can be tedious
|
| Java has had some type inference for almost 20 years, and local
| variable type inference (i.e. `var person1 = newPerson();`) for
| more than five.
| tasn wrote:
| I had no idea, thanks for letting me know. I'll update the post
| now.
|
| Java, I'm sorry for swearing at you all these years. :P
| tstrimple wrote:
| I've been in the same position. Modern Java is a solid
| language. Most "enterprise" companies are still using Java 8
| or if you're very lucky Java 12, so you really don't have
| access to all of the modern functionality and because of that
| I hated on Java for years. Java programming in the wild is a
| crap shoot at best.
| Zambyte wrote:
| > or if you're very lucky Java 12
|
| You mean 11, right? 12 was not an LTS release, and has been
| out of support for years. The currently supported LTS
| releases are 8, 11, 17, and the recent 21 release.
|
| https://en.wikipedia.org/wiki/Java_version_history
| beders wrote:
| The author is basically wrong on all the points. I used to think
| like that for decades, but in recent years changed my mind
| completely.
|
| Types lead to less bugs - nope, maybe marginally, but not
| significantly (see research on that)
|
| Types lead to a better development experience - nope, I have all
| the definitions and vars in my REPL and so has my IDE. I get
| completion on all symbols, I can look at call trees, usages,
| refactor things with confidence, run functions in isolation,
| replace them, wrap them, all from the REPL and _inside_ my
| application.
|
| We encode everything in the type system - you can't. You need to
| do runtime validation.
|
| And good luck untangling your type definitions when your
| requirements change. That one is the killer. Static types are
| premature concretions on the domain data model as you understand
| them now. They will change and if you are unlucky you will have
| to support multiple different variations of domain models in the
| same runtime. Good luck with that. Especially if you use
| inheritance.
|
| Granted, static types give compilers great leverage to optimize
| code, but, wouldn't you believe: there are dynamically typed
| languages that have static types as a la card add-on.
|
| But for many, many use-cases, especially enterprise development,
| a dynamically typed, immutability-first, functional language pays
| off dividends in the long run.
|
| The categorical error that is made by many strong typing fans is
| that they assume you would write the same code - just without
| types. Well, you don't.
| sanderjd wrote:
| It's an inevitably frustrating debate because everyone has just
| drawn totally different conclusions from their experiences. For
| pretty much all your points, my conclusions are the exact
| opposite. (Except for "You need to do runtime validation" - of
| course that's true; but you absolutely can avoid doing _most_
| runtime validation.)
|
| Just to take one somewhat at random:
|
| > _And good luck untangling your type definitions when your
| requirements change._
|
| I think it is exactly the opposite of the case that static
| types make it harder to adapt to changing requirements. In
| every dynamically typed system I've ever worked on, there have
| been important assumptions about data structures - sometimes
| checked dynamically in pre- or post- conditions, sometimes only
| checked in tests, and often simply not checked at all -
| scattered all around, such that changing requirements
| necessitated reasoning through the impact of the change on all
| these implicit assumptions. It was terrifying to make changes.
| Sure, easy to make a change and start up the application with
| the new code without a fuss. But to know whether the change
| broke some obscure codepath I hadn't considered or been aware
| of? Very difficult! I much prefer a static analysis pass
| saying, "hey, you changed this interface, did you know this
| codepath over here relied on that thing you changed?". Static
| type systems are not the only way to accomplish this, but in my
| view, they are a much less burdensome way to accomplish it than
| the level of dynamic validation and testing necessary to do so
| otherwise.
|
| But again, it's just a frustrating debate, because clearly you
| have the exact opposite experience! So where does it get us?
| Nowhere really...
| jjnoakes wrote:
| > I have all the definitions and vars in my REPL and so has my
| IDE. I get completion on all symbols, I can look at call trees,
| usages, refactor things with confidence, run functions in
| isolation, replace them, wrap them, all from the REPL and
| inside my application
|
| This is great, but it only works if you are executing the code
| that you want to inspect/complete/refactor. In my experience,
| that just doesn't scale well.
|
| > You need to do runtime validation.
|
| Type systems don't eliminate this, sure, but when used
| correctly, they _drastically_ reduce it, which is extremely
| useful.
|
| > And good luck untangling your type definitions when your
| requirements change.
|
| That's the best part - the compiler tells me exactly what I
| have to fix to get things working again. If I do the same thing
| in a dynamic language, I have to track things down myself, wait
| for unit tests to fail (hopefully I have 100% coverage...), and
| pray that there isn't an escape.
| at_a_remove wrote:
| Big yawn. I'm comparatively old and have programmed computers for
| a long, long time as one of those unfashionable "dark matter
| developers." What a lot of people see as unassailable truths I
| see as fads. Just as an example, I've never had to go wild about
| types. One day I will set aside some time to see if they're worth
| the overhead, but chances are I will not be a convert.
|
| Only _this_ toolchain will be used because it is the only one
| that makes _sense_. Everything will be so much easier if it we
| just did it in the functional style. Large programming projects
| can 't exist without Agile (I've actually heard someone say
| this). J++! _X_ Will Eat The World. No comments! Verbose
| comments! If we got the whole team on this one editor, imagine
| the synergy. Silverlight will take over the interactive web.
|
| If types turn into a big deal and remain that way say, fifteen
| years from now, then it is probably a Good Idea But Not Strictly
| Necessary. Whatever it is people are so bound up about, it is
| likely that programming used to happen without it.
|
| The only constants we have in programming are variables.
| coldtea wrote:
| > _The question around strong static typing is simple: would you
| rather work a bit more and get invariants checked at compile-time
| (or type-checking time for non-compiled languages), or work a bit
| less and have them be enforced at runtime_
|
| The latter. Other question?
| andrewclunn wrote:
| There are so many benefits for a front end application (written
| in javascript) to just assume it will be the backend that does
| type validation. A new field column added to a table? Cool,
| update the api layer, but the javascript just gets "the object"
| and now you have access to it immediately. No need to duplicate
| your definitions in both code bases, and it's not like front end
| security is real anyways. Sounds to me like a lot of "I learned
| to code in some derivative of C" programmers couldn't possibly
| consider that different languages could be optimized for
| different use cases and just want all coding to be "what they're
| used to." Then they moralize it and use shaming language to push
| it on everyone else. F typescript. I use different languages for
| different things, and strong typing makes a ton of sense IN MOST
| INSTANCES, but certainly not all.
| BigJono wrote:
| People are conflating too many ideas. You're right that there's
| a huge benefit to that, but it's contigent on you as the dev
| being able to trust the types coming into your system, you need
| good docs, and attention to detail as you code.
|
| All the TS devs just conflate JS with "no types" and picture
| drooling idiots that make random changes without knowing the
| type of anything (probably because that's what they do without
| 50 IDE popups to guide them). You're never going to convince
| them of the values of dynamic typing because they have a
| different mental model of it in their head.
| rdtsc wrote:
| That's why we like Python and Elixir but not Javascript which is
| weakly typed. :-)
|
| Since the author is willing to die for it, they might want to
| know that they probably meant "dynamically typed". Some
| dynamically typed languages are strong typed, too!
| tasn wrote:
| Author here. Please read the post, I actually said "Strong
| static typing" in the post itself (starting from the first
| paragraph), it just didn't look good in the title. :)
| rdtsc wrote:
| That's an important distinction. Why not just use "Static
| Typing". Yeah, the word "strong" sounds strong and cool, but
| since it's something you're betting your life on, it doesn't
| hurt to be a bit more precise.
| dartos wrote:
| Yeah, but your first point is specifically a weakness of weak
| types, not dynamic types.
|
| I don't really see any arguments against dynamic typing in
| there.
|
| Most strong, dynamically typed languages also have good
| developer tooling (elixir and dialyzer for example) and have
| built in ways of describing data structures.
| tasn wrote:
| There's a section about catching everything at compile time
| rather than runtime which is very much about. I think
| there's a lot of value at knowing when things go bad at
| compile time, rather than runtime.
| js2 wrote:
| Please add static to the title. Most of the comments are
| referring to the current title and haven't read the article.
| tasn wrote:
| Yeah, I just did, thanks!
| leroman wrote:
| As an extension to this, strong typing is a gateway drug to
| generics.
|
| Strong typing really shines when you have generics, saving bugs
| at one level above basic types..
| hospitalJail wrote:
| You got me to look up 'generics'.
|
| I like the idea, feels very pythonic ironically. And I suppose
| if you don't want the generic, I imagine there is probably some
| subclass of that which is more restrictive.
|
| Anyway, as a developer I love when people do this. As a
| developer this sounds like a nightmare to maintain. My
| coworkers have told me to limit the numbers of 'what ifs' and
| just roll with it.
| marcosdumay wrote:
| > feels very pythonic ironically.
|
| Look at duck typing.
| leroman wrote:
| You can think of generics a meta-language that restricts and
| documents some behavior one level above the concrete types
| that you might need.. Lots of benefits, code re-use,
| documentation as code, less bugs..
|
| Granted it's not always easy and straight forward but that
| what senior developers in the team are for..
| alickz wrote:
| Swift makes good use of generics in my experience
|
| https://docs.swift.org/swift-book/documentation/the-swift-
| pr...
| leroman wrote:
| I haven't got a chance to use Swift but it looks nice!
| mcv wrote:
| I just had a moment today. I'm developing a front-end thing in
| TypeScript. I'm messing around with dates across different data
| types (date string, Moment, a Neo4j-compatible date type, and
| Javascript's own Date type). Real fun, as you may understand.
| Struggling to convert a specific type straight to a js Date, I
| decide to just `new Date()` and add all the fields I need.
| `jsDate.setMonth(convert(otherDate.month))`. Red squiggly line
| appears underneath. I first realise it's a js Date, so I add a
| -1: `jsDate.setMonth(convert(otherDate.month)-1)`, and the _red
| squiggly line disappear_.
|
| I feel a moment of horror. _Type coercion._ In front of my very
| eyes! I quickly added proper conversion everywhere.
|
| I have no problem with dynamic types, but type coercion is the
| devil.
| bluGill wrote:
| The problem with strong types is how strong is right?
|
| If you have a truck with a 1000 liter tank on the back the type
| for the contents liter, or is it something liters_H2SO4 - if you
| only need to go to a gauge liter is good enough, but if you are
| doing anything else you do not want to mix the contents up with
| liters_H2O. Note that is is very likely you will want to have
| both in the same program in different areas! Of course we can
| take the tank out of the truck and replace it with a box of iron
| - so maybe we need an even more generic type that could be either
| liters or kg?
| craigmoliver wrote:
| I don't care how many times I see this argument; strong typing is
| correct. We need to keep beating this drum because every year
| there are more and more new developers that know nothing. We need
| to make good one that aren't ignorant of history and what
| works...because the more things change the more they stay the
| same.
| AlchemistCamp wrote:
| I have to wonder if the author has ever used a strong,
| dynamically typed functional language like Clojure or Elixir or
| if his dynamically typed language experience is limited to
| JavaScript, Python and very similar languages.
|
| It's very easy to make up one's mind about something and then
| completely stop learning.
| tomtheelder wrote:
| I have worked extensively in Elixir and it only made me feel
| more strongly that static typing is the way to go. The sheer
| mental overhead caused by the lack of typing in Elixir is the
| biggest productivity killer for me when working in that
| language, and refactoring is almost as much of a nightmare as
| it is in something like JS.
|
| For me, strong and dynamic is the worst possible combination. I
| actually need to be precise with types, but the language gives
| me no help.
|
| I think Elixir has the best combination of runtime and tooling
| and ecosystem out there, and it's type system is the only thing
| that prevents me from using it for nearly everything.
| spprashant wrote:
| Asking because I am curious to learn, how does a language being
| functional matter here?
|
| As I understand it Python is also strongly typed, while
| JavaScript is not.
| AlchemistCamp wrote:
| In Python, variables are mutable and being a class-based OO
| language, there's often a lot of state that isn't immediately
| clear when inspecting nearby code.
|
| By working with immutable structs and pattern matching, you
| can get many (but not all) of the same guarantees you would
| from static types.
| ceving wrote:
| Guy L. Steele: "Don't you think it is ironic that type theorists
| who want to talk about strongly typed languages talk to
| themselves with an untyped language"
|
| https://youtu.be/dCuZkaaou0Q?feature=shared&t=539
| mrkeen wrote:
| No I don't.
|
| Now go and rewrite your dynamic language's runtime in a dynamic
| language.
| ozr wrote:
| There's been innumerable runtime errors, both tiny and world-
| altering, as a result.
| Tade0 wrote:
| > or even worse not enforced even at runtime (JavaScript, I'm
| looking at you... 1 + "2" == 12).
|
| I'm having trouble taking seriously a post that beats this dead
| horse.
|
| Sure, it's there. It's even documented in the language
| specification, but now that we have template literals it's rarely
| used because truly, what is the expectation when using addition
| on two variables of different types?
|
| As for static typing:
|
| Grug put it eloquently: https://grugbrain.dev/
|
| > grug very like type systems make programming easier. for grug,
| type systems most value when grug hit dot on keyboard and list of
| things grug can do pop up magic. this 90% of value of type system
| or more to grug
|
| > big brain type system shaman often say type correctness main
| point type system, but grug note some big brain type system
| shaman not often ship code. grug suppose code never shipped is
| correct, in some sense, but not really what grug mean when say
| correct
|
| In my opinion static typing is useful and I wouldn't start a
| commercial project without it. That being said I think it's
| productive to practice programming in dynamically typed
| languages, because:
|
| -You avoid the sort of type golf that happens with a sufficiently
| powerful type system(I regret every use of the `infer` keyword in
| TypeScript).
|
| -The situation forces you to be radically explicit.
|
| -You can explore situations that would normally be
| hard/impossible to type.
| graypegg wrote:
| I still bemoan the half-assed RBS type system in Ruby 3. I think
| Ruby actually had a cool chance to explore what inline type hints
| would look like in a very meta-programming-y environment. While
| RBS works, it's a hassle to keep updated, and I think adoption is
| just going to remain low forever sadly.
|
| Sorbet [0] is close, just wish the syntax wasn't as verbose as it
| is.
|
| Crystal Language [1] is even closer, I just wish it had better
| IDE support.
|
| [0] https://sorbet.org/
|
| [1] https://crystal-lang.org/
| berkes wrote:
| I'm worried that the reluctance of the Ruby community to adopt
| some typing, might push it further into obscuration.
|
| For me, full time Rubyist for over a decade, it was enough to
| "jump ship" to Rust and TypeScript. It's one more reason to
| forego Ruby, I fear.
| throwawaaarrgh wrote:
| Typing is literally an architectural/design decision. There is no
| such thing as one single type system that works for all use
| cases.
|
| It's like saying there's only one good kind of metal fastener for
| construction. Sometimes you should use nails, sometimes screws,
| sometimes bolts. It's not like one of those is always superior to
| the others. You literally should not use a bolt all the time, nor
| a screw, nor a nail. There are specific engineering requirements
| and purposes to them all and you can't just mix and match based
| on your personal preferences.
|
| Well, let me correct myself: you _could_ just use one fastener
| you prefer, but your building would fall apart six different ways
| and be a huge pain in the ass to construct. Thankfully we have
| building codes so people can 't just decide to do that.
| berkes wrote:
| I doubt anyone is arguing that our bash scripts should be
| typed, or our quick "remove_currency_from_bank_csv.py" must be
| statically typed.
|
| The article puts a few cases forward. What the article is
| discussing, however, is the majority of software. Built in
| varying teams. Over long periods of time. Large software,
| complex software.
| irrational wrote:
| I wonder if most opposition (or even ambivalence) towards strong
| typing comes from never having used it. If your entire career has
| been JavaScript, Python, shell scripts, etc.; then you have zero
| experience with it.
| ilaksh wrote:
| I taught myself Turbo Pascal in middle school (34 years ago)
| and C/C++ in high school. (Both typed).
|
| Over the years, I have done programming with C, C++, Java, C#,
| PHP, Python, OCaml, Lua, Nim, Golang, Rust, Objective-C, Flash,
| Bash, D, Scala, TypeScript, assembly, PL/SQL, F#, and a few
| that I am forgetting.
|
| Compile time type checking can definitely make things easier.
|
| But for dynamic languages that I have been programming in for
| many years to have types shoehorned into them as an
| afterthought feels like a kludge.
|
| And it's a tradeoff. I got used to developing in Node or Python
| with vim without auto completion (although I had those things
| as a kid in IDEs for other languages and they can be great).
| And without compile time type checks.
|
| You can pass JSON around and literally never do a database
| migration.
|
| This stuff will lead to more runtime errors initially, but also
| means more streamlined code. And you have to do thorough
| testing regardless.
|
| TypeScript might be a choice for a large project with several
| developers. But I would also argue that an even better choice
| would be just to use a different language that has the typing
| system you want built in rather than awkwardly bolted on.
|
| What I see in most TypeScript projects is a half-assed attempt
| that still results in run time type errors, but with the added
| "benefit" of an awkward bolted on typing system and the need
| for more tools as well as losing any dynamic benefit.
|
| They drop the idea of using JSON and make everything related to
| the database compile time checked if possible. I'm not saying
| that those checks can't be useful but if are going that route
| it would make more sense to just drop the dynamic language.
|
| Having all of the dynamism can be a convenience and save you
| time and effort in other ways. But not if you treat it as a
| poor man's static language and shoehorn in types in a half
| assed way using a traditional database.
|
| Part of this is that people think software engineering is about
| your choice of stack or adding processes to development.
|
| What matters most is probably the feedback loop between the
| users and the developers. Starting with the requirements
| engineering. Second to that would be details of the software
| design and organization. Leveraging existing code effectively
| can be key. Using descriptive but relatively concise
| identifiers, short functions, good code organization.
|
| But diving into and evaluating all of that stuff in detail
| takes effort and a lot of skill and so many make snap
| judgements based on surface level processes or tool selection.
| siva7 wrote:
| You probably mean static type checking. I've used strong typing
| in the first half of my career and have no hard feelings about
| it. So no, the opposition isn't about no experience with one or
| the other.
| randomdata wrote:
| Python is strongly typed. If your entire career has been
| Python, you will have a lot of experience with it.
|
| Static typing, maybe not so much.
| tonyedgecombe wrote:
| I wonder if most opposition (or even ambivalence) towards
| strict typing comes from never having used it. If your entire
| career has been JavaScript, Python, shell scripts, etc.; then
| you have zero experience with it.
|
| @irrational Sorry for the plagiarism.
| bjourne wrote:
| The discussion over whether strong typing is better than weak
| typing is settled [1], but not over whether static typing is
| better than dynamic typing. Adherents of static typing thinks
| that the compiler should check "correctness" by verifying type
| invariants, adherents of dynamic typing think that is a waste of
| time.
|
| I'm firmly in the latter camp. Because the compiler can't check
| _program correctness_ only _type correctness_. Type correctnes is
| necessary for program correctness, but _NOT_ sufficient. Static
| typing adherents fail to recognize this, thus falsely believing
| that static typing guarantees them more than what it actually
| does (blub).
|
| Consider the article's birthdayGreeting example. Author is happy
| that static typing catcges the birthdayGreeting("John", "20") bug
| because "20" is not a number. But birthdayGreeting(" ", 123) is
| not caught (" " is not a name) and neither is
| birthdayGreeting("Anna," -12335). birthdayGreeting("Anna" 4.5),
| though, is caught, which arguably is wrong since 4.5 is an age.
|
| This is actually very important since "type bugs" are trivially
| easy to catch, while "semantic bugs" can stay undetected for
| years. An account balance stored as a uint that overflows, a
| number that must be prime at a certain program location, but
| isn't, a list that must not be empty, etc. No, not even dependent
| types can guarantee these invariants.
|
| If you don't believe me, read up on some catastrophic bugs. Those
| that have caused space ships to explode and cars to crash. To the
| best of my knowledge, _not a single one_ has been caused by bona
| fide type errors. In the overwhelming majority of cases, the root
| cause has been a semantic error.
|
| [1] - Most people don't understand that typing is measured over
| at least two axes, strong/weak and static/dynamic, and continue
| to conflate weak typing with dynamic typing. C is statically
| typed _and_ weakly typed. Python is strongly typed _and_
| dynamically typed. Javascript is weakly typed _and_ dynamically
| typed.
| eyelidlessness wrote:
| Many of your examples could definitely be caught by static
| types, depending on the type system. But that's less important
| than...
|
| > This is actually very important since "type bugs" are
| trivially easy to catch
|
| This, IMO, is _exactly_ why I'm in the static type camp. It's
| so trivial that you can do it declaratively, inline with the
| code it's testing, with instant feedback, at every call site
| and in every downstream expression /statement. A type
| annotation doesn't mean my semantic/domain logic is sound, I
| still have to test that. but it could replace dozens of trivial
| tests _orthogonal_ to the logic I care about... tests which,
| let's face it, few people are going to write exhaustively
| otherwise.
| perrygeo wrote:
| The amount of runtime checks and/or tests required to emulate
| the guarantees of static types is huge. It's perplexing that
| some people would rather do that manually.
|
| But to the point of triviality, static types tend to lull
| developers into a false sense of security. There are limits
| to their usefulness. You still need both runtime checks and
| test-time assertions for your logic. You just need less of
| them and they provide more value per line of code. But I've
| never seen a type system capable of expressing the entire
| problem domain in an ergonomic way. Not even close.
|
| For my money, a combination of: static types, property-based
| testing, unit/integration tests, and an end-to-end test
| against prod are all required. You can compensate for the
| lack of one by putting more effort into another but you're
| really just shuffling the "correctness burden" from one place
| to another. I like static types because it makes the rest of
| testing easier. But at some point, you've got to roll up your
| sleeves and make sure it works IRL.
| prewett wrote:
| In a dynamically language you _need_ 100% test coverage,
| because misspelling a variable name turns into a runtime
| error.
|
| On large projects this can be a problem. I worked on a
| Python server some years ago, and with every large program
| that supports exceptions, there's a catch block somewhere
| that silently eats the exceptions it doesn't process. Well,
| some modules were loaded dynamically, so my first spelling
| mistake (and second and third...) took quite a while to
| debug because things just didn't work, the code didn't get
| executed, but there were no errors. This also ate syntax
| errors, too, since that is also an exception. So if you
| edited the file, you had no idea if things actually still
| worked (or even compiled!) until you tested the
| functionality from the file.
| sanderjd wrote:
| I question this "false sense of security" point. In my
| experience, people who prefer as much static analysis as
| possible, mostly based on types, are also more likely to be
| thinking about invariants and error cases more generally. I
| would go further to say that anyone who has really adopted
| a thinking-about-invariants-and-error-cases style of
| programming has almost certainly become frustrated with the
| amount of repetitive validation code required to accomplish
| that in projects with no static analysis of types.
| alpaca128 wrote:
| > Because the compiler can't check program correctness only
| type correctness
|
| How is this evidence for it being a waste of time? No solution
| is perfect yet many are worthwhile.
| sanderjd wrote:
| The specific examples you chose to illustrate this point are
| interesting, because to me, it is clear that what you want is a
| `Name` type that always represents a valid name and an `Age`
| type that always represents a valid age. Then you can put the
| validation in a single place (the constructors of those types)
| and write many methods like `birthdayGreeting` that can happily
| use values of those types without needing to take on the
| responsibility of validating them.
|
| I honestly don't know of a good way to implement this pattern
| without type checking or at least optional type hints and
| static analysis. Instead, you can do validation of the input
| values in every single method, which is hugely burdensome, or
| you can assume callers are passing you valid values and write
| tests to make sure it isn't too catastrophic if they don't. I
| don't find either of these solutions satisfying.
| suby wrote:
| You didn't provide an argument for why static typing is not
| worthwhile, merely that it won't solve all of your problems --
| thus, you concluded, dynamic typing is better.
|
| Yet static typing does very much catch issues, so I really
| don't see where you're coming from with this.
| bjourne wrote:
| If I'm being generous then maybe 5% of my developer time is
| spent chasing type errors. And then most of those "type"
| errors would be errors that no reasonable type system would
| have a chance of catching - like keys missing from
| associative arrays. I'm competent enough to not need the
| compiler to tell me banalities like that age is a number or
| name a string. The overhead of having to deal with types is
| many times larger than those 5%.
| _dain_ wrote:
| _> And then most of those "type" errors would be errors
| that no reasonable type system would have a chance of
| catching - like keys missing from associative arrays._
|
| what? in a language with ADTs and exhaustiveness checking,
| accessing a key from an associative array will give you
| back an Option type and the compiler will force you handle
| the code path where the key is missing.
|
| unless I've misunderstood what you meant, this is a
| _canonical_ showcase of what modern static type systems are
| good for.
|
| and in your parent post:
|
| _> a list that must not be empty, etc. No, not even
| dependent types can guarantee these invariants._
|
| what do you call haskell's NonEmpty then? https://hackage.h
| askell.org/package/semigroups-0.18/docs/src...
| data NonEmpty a = a :| [a]
|
| I think you're underestimating what static types can do.
| it's funny you mention "blub" in that post ...
| marwis wrote:
| How does [1] in any way support the claim made in first
| paragraph?
| digging wrote:
| I don't understand how you go from "this tool only does 90% of
| the work I need it to" to "I'll do the whole thing by hand"
| instead of "I'm fine doing 10% by hand".
| kpozin wrote:
| > read up on some catastrophic bugs. Those that have caused
| space ships to explode and cars to crash.
|
| One of the most famous type errors in recent history did in
| fact crash a spaceship.
|
| https://en.m.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_o...
| MayeulC wrote:
| > Those that have caused space ships to explode
|
| It's funny you should mention this, as it immediately brings
| [1] to my mind. This well-known incident was due to type-
| checking, with acceptable ranges defined ahead of time for some
| types (which resonates with your comment: make birthdayGreeting
| accept ranges 1-150 or something, easy to do in ADA).
|
| There are a few more well-publicized issues with spacecraft
| that could have been caught with better type-checking,
| including metric/imperial conversions (why not build the unit
| into a type? Though the fault probably was with integration
| testing for [2]).
|
| Of course, you are right that type checking can't find every
| code issue (especially algorithmic), it doesn't replace tests.
| Instant feedback and type hints are invaluable during the
| development phase, though.
|
| In your example, one could probably replace the first name
| string by a person type/object, by the way.
|
| [1]: https://en.m.wikipedia.org/wiki/Ariane_flight_V88
|
| [2]: https://en.m.wikipedia.org/wiki/Mars_Climate_Orbiter
| bjourne wrote:
| Neither of those were "bona fide _type errors_ ". The fact
| that both errors ocurred _while using statically typed
| languages_ shows that. The orbiter failed because inches were
| interpreted as centimeters. But as both datums were stored as
| floating point numbers, which they always would be, in any
| reasonable implementation, static typing wouldn 't have
| caught anything. The Ariane failure was due to a cast of a
| double to a short resuling in an overflow. Again, not
| something static typing can catch because it can't statically
| check the value of an arbitrary double.
|
| No, even more types is not the solution. It's not pratical to
| wrap every measurement in a Meter or Inch type
| (standardization is one issue, is my Meter type the same as
| your Meter type?) and it doesn't significantly increase the
| amount of invariants checked. You still have range issues and
| you still won't get a statically check PrimeNumber type.
|
| I'm not familiar with ADA, but VHDL has similar range
| constraints which are runtime checked.
| thfuran wrote:
| >But as both datums were stored as floating point numbers,
| which they always would be, in any reasonable
| implementation
|
| It doesn't strike me as inherently unreasonable to use
| fixed point. At any rate, there are languages with built-in
| unit systems, so you could declare something like float
| length = 4.5 <m> and get an error if you try to add it to
| something in a different unit without having to roll your
| own dimensional analysis framework.
| bjourne wrote:
| Of course, fixed point would have been a reasonable
| choice too. But here is my point. Someone who likes
| testing could say "This bug would have been caught with
| better testing". Someone who likes static typing could
| say "This bug would have been caught if they had used an
| esoteric type system with support for physical
| quantities." ... Which no one uses. Thus, you have an
| argument between something real and realistic, and
| something imagined and unrealistic.
| thfuran wrote:
| That you aren't familiar with something hardly makes it
| imaginary. That exact formulation of unit system is, I
| think, pretty uncommon, but there are widely used
| languages (vhdl) where uniting is more directly part of
| the type system and widely used uniting systems as
| libraries (boost) where it is not directly a language
| feature.
| vouwfietsman wrote:
| > The fact that both errors ocurred while using statically
| typed languages shows that
|
| Obviously it doesn't, since you can make a statically typed
| language program where every variable is a string map and
| every function takes variable args, and have no help from
| your compiler at any time because every type is always the
| right type. Sounds stupid, but in fact this is what
| happened in the examples.
|
| The examples _are_ bona fide type errors, because even
| though a statically typed language is used, multiple
| different _types_ of numbers _got the same static type_
| causing the issue. So the people here were offered the
| solution to their problem from their domain (two types of
| numbers), choose to use dynamic typing (make both a float
| even though they 're different things), causing the
| compiler to have no way of statically checking their code,
| and that caused a bug. It's the opposite of a counter
| example.
|
| It is in fact _the absence of enough typing_ that caused
| these issues. How much more typing do you need :)
| nyssos wrote:
| > But as both datums were stored as floating point numbers,
| which they always would be, in any reasonable
| implementation, static typing wouldn't have caught
| anything.
|
| Types are not runtime representations, and any good nominal
| type system will allow you to avoid this sort of problem
| easily. For example, this Haskell code
| newtype Inches = Inches Double deriving Num newtype
| Centimeters = Centimeters Double deriving Num
| a :: Centimeters a = Centimeters 1.0 b
| :: Inches b = Inches 1.0 fine = a + a
| alsoFine = b + b mistake = a + b
|
| will give this type error Couldn't match
| expected type 'Centimeters' with actual type 'Inches'
| In the second argument of '(+)', namely 'b' In
| the expression: a + b In an equation for
| 'mistake': mistake = a + b
|
| but both `a` and `b` will be doubles at runtime.
| bjourne wrote:
| That is why I wrote "in any reasonable implementation".
| Embedding physical quantities in the type system is
| possible in many language but is not practical. Hence why
| safety-critical software doesn't contain declarations
| like yours. For example, what is the type of Inch * Inch?
| What is the type of Inch / Inch? Sure, perhaps _if_ NASA
| and their subcontractors had used a common well-developed
| physical quantities library then the bug could have been
| caught during compile-time. But I think it is a moot
| point since most people don 't use such libraries.
| esafak wrote:
| > For example, what is the type of Inch * Inch?
|
| An area, inch^2.
|
| > What is the type of Inch / Inch?
|
| A unitless ratio?
|
| I don't understand why this is not practical in safety-
| critical software. nyssos demonstrated what I believe is
| the right way to do it.
| bjourne wrote:
| These semantics make the type incompatible with the Num
| class and attempting to plug your type into, say, a run
| of the mill ode solver likely won't do what you want. So
| you have two options. 1) Rewrite all code to become
| "quantity aware". Multiplying two Matrix[Inch] results in
| a Matrix[Inch2] and so on. 2) Litter your code with
| floatToInch and inchToFloat conversions. I think you can
| see why both options suck? If you really can't, then
| perhaps try finding some safety-critical software that
| relies on "physical quantity types" in some form or
| another?
| esafak wrote:
| In that case you could make the unit a property of the
| matrix, and have the second matrix be unitless, or vice
| versa. The point is you have to do a little more work,
| and you may not be able to use your existing classes, but
| it buys you safety.
|
| What languages do you use for these things, so I can
| understand how they deal with physical quantity types?
| mrkeen wrote:
| Thanks for mentioning blub I guess.
|
| If you program in a dynamic language, then you have no choice
| but to _perceive_ all bugs as runtime bugs. Because every bug
| _you witnessed_ was a runtime bug, so why would types have
| helped you?
|
| When I program in a typed language, the compiler rejects
| programs I write _all the time_. Things like: putting code that
| can 't be rolled-back in the middle of a transaction.
| scarmig wrote:
| In principal, at least, you could encode all those constraints
| in the birthday example into the type system. In practice, no
| one does, partially because existing type systems aren't
| ergonomic enough to express those constraints for developers to
| want to use them.
| tasn wrote:
| > Consider the article's birthdayGreeting example. Author is
| happy that static typing catcges the birthdayGreeting("John",
| "20") bug because "20" is not a number. But birthdayGreeting("
| ", 123) is not caught (" " is not a name) and neither is
| birthdayGreeting("Anna," -12335). birthdayGreeting("Anna" 4.5),
| though, is caught, which arguably is wrong since 4.5 is an age.
|
| Author here. I think your examples illustrate my point rather
| than provide a counter example.
|
| I mentioned later in the post that we validate when creating
| the type (from e.g. user input) so we know that the `Name` type
| is always valid (and " ") is not a name. So the type ensures
| that we have a valid name. So this will definitely be caught in
| our codebase.
|
| As for birthdayGreeting("Anna" 4.5) and
| birthdayGreeting("Anna," -12335), number means a float in JS so
| it actually would be valid, though admittedly I had full
| integers in mind when writing this. Another example of where
| stricter typing than what TS providers (which Rust does!) would
| have helped better define the invariant.
|
| So in short: the problem in the code there was that I was
| trying to show a simple example, which means I didn't define
| all the types as strictly as I normally would have, and it
| surfaced more bugs that would have been caught with types.
| ddellacosta wrote:
| "Strong typing" was a poor choice of terminology here.
|
| https://en.wikipedia.org/wiki/Strong_and_weak_typing
| derbOac wrote:
| Strong static typing is better when used well, but worse when
| it's used poorly.
|
| That last part is the catch, and I've seen plenty of people think
| they're using it well when they're actually using it very, very,
| very poorly.
|
| Dynamic typing isn't just a convenience sometimes, sometimes it
| helps compensate for poorly planned type structures.
|
| Like a lot of things, there are tradeoffs in terms of what types
| of errors you want to avoid more.
| cocoacat wrote:
| But in my experience I have also experienced the opposite. I
| have seen people casually reuse variables by reassigning them
| to a new type or developing a single function that returns
| different types. With dynamically typed languages it sometimes
| feels like you can take messy shortcuts because they let you.
| hospitalJail wrote:
| I think I agree.
|
| Probably the biggest issue with python.
|
| Seemingly random changes between float64 and object happen when
| doing unit testing(pandas).
|
| Can't remember the exact situation because I switched to While
| permanently, but there was some For loop problem. If the data
| came in as length 1, the for loop would read the individual chars
| of the string. If it came in as >1 it would iterate through the
| list.
|
| 15 years ago when I started python, maybe it made sense. Probably
| ~5-6 'oof that was a bug I wasted time' in 3 years professional
| use. Today, I find myself forcing types to solve a bug, or at a
| minimum checking the types as the program progresses.
| ledauphin wrote:
| yeah, this isn't Python, this is pandas. Run far away from
| pandas if it's not too late.
| nathan_compton wrote:
| Pandas is a particularly absurd library.
| falcor84 wrote:
| Pandas's flexibility is amazing for exploration and
| prototyping. I'm actually a huge fan of the gradual typing
| approach, whereby you can start just messing around with
| stuff in a notebook, and then add the types and the rest of
| the structure once you are ready to solidify your design.
| nathan_compton wrote:
| Pandas is a shit show compared to dplyr in R and even
| compared to polars.
| reportgunner wrote:
| This is not at all exclusive to pandas.
| dist-epoch wrote:
| > Pandas's flexibility
|
| What you call flexibility I call non-readability:
| df.ix[0] df.loc["x"] df.loc["x", :]
| df.iloc[0] df.x df.x[0] df["x"]
| df[["x"]] df[df["x"]] df["x", 0]
| df["x"][0] df[:, 0] # and probably a few more
| I forgot
|
| If you stop working with it for 2 months you forget what
| each one is doing and when you are supposed to use it.
| falcor84 wrote:
| I'm not clear what your argument is. Many of your
| examples are just syntactical sugar which you can very
| easily ignore, and even prohibit in your linter.
|
| Also, note that pandas's datafrimes shine when you focus
| on column operations, if you're finding yourself
| accessing individual elements by index often, that's
| usually a sign that you should switch to a more
| appropriate data structure.
| dist-epoch wrote:
| > I'm not clear what your argument is.
|
| That when you look at online examples or other people's
| code you will find all of these variants used.
| falcor84 wrote:
| Looking at random people's code online is like staring
| into the abyss. I sometimes see APL code and find myself
| running in circles and screaming for a bit before I
| regain my composure, but I don't think that's reason
| enough for me to complain about APL's design.
| dist-epoch wrote:
| There are alternatives to Pandas, for example Polars
| doesn't have this problem.
|
| Sure, doing an operation in Polars can be more verbose,
| but it really does have just a few ways of doing things.
| Which in the end is actually more productive, since you
| don't need to always google the syntax.
| dist-epoch wrote:
| > If the data came in as length 1, the for loop would read the
| individual chars of the string. If it came in as >1 it would
| iterate through the list.
|
| You probably did this: for name in ("John"):
| # "J" # "o" # "h" # "n" for
| name in ("John", "Sam"): # "John" # "Sam"
|
| The correct form for the first one is this: for
| name in ("John",): # "John"
| reportgunner wrote:
| I don't understand how someone can use pandas if they have a
| choice to use something else. It almost feels like a language
| of it's own.
| m0llusk wrote:
| Seems like a matter of degree.
|
| If taken to an extreme then nearly all parameters can be made
| into unique types. Not just measures, but pixel height measures.
| Not just pixel height measures, but help panel pixel height
| measures. Not just help panel pixel height measures, but settings
| help panel pixel height measures and so on. This may seem like a
| great way to keep everything well sorted, but ends up being an
| unhelpful mess that is difficult to maintain. So the question is
| how exactly in a situation is best to define types, not whether
| or not to have them or to make them static or whatever else.
|
| And why exactly do you need types in the first place? Lots of
| projects are messy and involve teams and have work handed off to
| developers on a regular basis. In that kind of context which is
| quite common types can be a life saver. There are also short term
| one person projects that have a high expectation of all work
| being thrown away soon after. Isn't defining a bunch of types
| likely to be a waste of time if there is only a brief development
| effort which is clear and not expected to ever be touched by
| teams?
|
| Most one size all solutions like static typing have some contexts
| in which they are either a complete waste of time or need their
| breadth to be carefully limited.
| michaelfeathers wrote:
| I always have trouble with takes like this because they are
| context-free. There are a wide variety of project types and
| development scenarios.
|
| My nuanced take is that typing is an economic choice. If the cost
| of failure (MTTR and criticality) are low enough it is fine to
| use dynamic typing. In fact, keeping the cost of failure low (if
| you can) gives you much more benefit than typing provides.
|
| Erlang, a dynamic language used to create outrageously resilient
| systems, is a great example of that for the domains where it can
| be used.
|
| I'm not a dynamic typing zealot (I like static typing a lot) but
| I do think that dynamic typing is unfairly maligned.
|
| The cost argument brings the decision down to earth.
| KMag wrote:
| Some early Lisps had both compiled and interpreted mode, where
| the interpreter used dynamic scoping and the compiler used
| lexical scoping. (Which, I presume, caused much developer
| confusion when code worked fine in the interpreter and got very
| strange behavior once compiled.) Something analogous (but more
| sane) could be done with type systems.
|
| I'm very much a fan of strong static typing, but I understand the
| appeal of dynamic typing, particularly for small scripts and/or
| prototypes.
|
| Static type checkers (for most languages) are pretty simple
| theorem provers. For statically typed languages, the compiler
| (or, I suppose in rare cases, interpreter) rejects any program
| that it can't prove is free of type errors. An alternative would
| be to only reject programs that provably contain type errors. The
| difference in allowed programs covers the cases where the type
| checker can't prove either way.
|
| So, I'd love a language with a type checker that when ahead-of-
| time compiling code would refuse to emit libraries/binaries when
| it couldn't statically prove types were used correctly. In
| interpreted mode, it would only refuse to load code that it could
| statically prove contained type errors. Maybe when used within an
| interactive session, it would still allow (but warn) when code
| provably has type errors.
|
| As an added bonus, static type guarantees open up more
| opportunities for the optimizer. A single language offering some
| range of static guarantees would reduce the number of cases where
| dynamically typed code gets re-written into a higher performance
| statically typed language when re-factored into libraries.
|
| If you prefer, go ahead and dynamically type your scripts, etc.
| However, if/when it comes time to package up parts of your
| program for wider re-use as libraries, please tighten up the
| static guarantees of type safety.
| davepeck wrote:
| Back in the early 2000s, when I was a wee new SDE at Microsoft,
| there was a shared whiteboard down the hall from my office on
| which someone had scrawled:
|
| "STRONG TYPING IS SO 90s!"
|
| That missive stayed on the board for over a year. I still think
| about it from time to time and remember that the tech world's
| pendulum is always in motion.
|
| Today? I adore TypeScript and I'm pretty excited about the PEP
| 695 QOL improvements to type annotations in Python 3.12. Where
| types and tools are concerned, we're in a much better place today
| than when Nirvana was still the next big thing.
|
| But I won't be surprised at all if in another decade I see
| "STRONG TYPING IS SO 20s" marked on some corporate whiteboard in
| Redmond. :-)
| choeger wrote:
| First of all: I always have and always will be a proponent of
| statically strongly typed languages (although I would argue that
| "statically strongly" is redundant here, there are only typed and
| untyped languages, IMO).
|
| But there's one cost that the author seems to miss and that I
| didn't fully appreciate for some time. That's the cost of
| composition. If you look at python you can pretty much compose
| all possible packages on pypi in your project. All their means of
| abstraction are usually fully compatible (except for
| concurrency). Composition often only requires a little bit of
| glue code.
|
| In a statically typed language's ecosystem you will probably a
| handful of fundamentally different means of abstraction like
| functors vs. classes that simply don't compose well together.
| Hence the fragmentation increases massively.
| heisgone wrote:
| Strong typing is what allowed me to be a developer. I was never a
| great developer but I was good enough to be worth my salary. I
| was not smart enough to maintain a complete mental model of a a
| weak-typed software but I was able to do fairly complex stuff
| with the safety net of strong typing. My software developer would
| have ended much sooner (or never have been) without strong types.
| I had not other choice but to live or die on that hill.
| ctenb wrote:
| > There are definitely uses for untyped languages (or language
| variants), for example they are much nicer when using a REPL, or
| for throwaway scripts in environments that are already hopelessly
| untyped (e.g. the shell).
|
| I think nushell disproves this example :)
| mik1998 wrote:
| Static typing is useful if you are building some program for
| other people to run that you want to be reasonably robust.
| However, it does not work well with interactive programming. If I
| had to declare all the types every time I do something in
| Mathematica, I'd be severely annoyed for no benefit.
|
| Common Lisp seems to be the best of both worlds, with dynamic
| strong typing in general and advanced compiler type inference
| that can correctly point out mismatched types in most cases in
| SBCL, leading to much easier time programming interactively.
| loup-vaillant wrote:
| You are complaining about _explicit_ typing.
|
| Try ML (OCaml, F#...) or Haskell, they have type inference. No
| need to declare types most of the time, but they're there,
| checked at compile time.
| DevKoala wrote:
| The best engineers I've met are business objective driven. Strong
| vs dynamic typing is often a secondary concern. I understand the
| arguments for each approach, but I've never understood those who
| are dogmatic about their preferences.
| loup-vaillant wrote:
| > _There are advantages to not using types, such as a faster
| development speed_
|
| In my experience, not even that. Static typing _speeds up_ my day
| to day programming.
|
| You touch this point on later with how IDEs can make your
| experience nicer with static typing, but I see this even with a
| REPL: statically detected type errors lead to meaningful error
| message that are much closer to the actual root cause, and let me
| fix it quicker than a runtime error would have.
|
| It also liberates my brain from having to think so carefully
| about types. The compiler is disciplined so I don't have to be. I
| can move quicker, with the confidence that a huge class of errors
| will be caught right away.
|
| Static type systems are in my experience easier to use, speed up
| development, and increase reliability. The costs? So far I've
| seen only two: they may be harder to learn, and they're harder to
| implement.
| jodleif wrote:
| Some would argue that exactly that thinking is what makes the
| software cleaner and better- rather than mush-mash that passes
| the compiler. I.e what I'm saying is that it might be good to
| be thinking about exactly what you're passing in, out and why.
| tines wrote:
| Isn't this the same argument that says that we should all
| write assembly, because you should have to think harder and
| really know what you're doing?
| AnimalMuppet wrote:
| Of course it's good to think about what you're passing, and
| why! Nobody disagrees with that.
|
| The issue is, _can_ you think carefully enough, consistently
| enough, so that you don 't need static types? Can your
| coworkers - _all_ of them? What about future you, and your
| future coworkers? What about that time that you 're in a
| hurry, or going on vacation the next day, and you're not at
| the top of your game?
|
| If computers have taught us anything, it's that automatic
| processes are more reliable than manual ones.
|
| Personally, I just inherited a code base that is a decade
| old. I haven't measured, but I'm pretty sure that it's more
| than 100,000 lines. My current coworkers have two weeks
| longer on the code base than I do. Static types make this a
| _lot_ easier.
|
| And, if your approach to static typing is "mush-mash that
| passes the compiler", no, static typing may not save you. But
| dynamic typing wouldn't, either, with that approach.
| jodleif wrote:
| Can't say I agree. Having spent about 50/50 of my career
| doing weak/strong typing Im more and more convinced it's
| very rarely I miss static type-checks. Though I have been
| blessed with skilled coworkers and sane languages.
| laserbeam wrote:
| I work a lot in python. I hate it.
| pphysch wrote:
| I have come to believe that static typing zealots haven't worked
| seriously on a large variety of (shipped) software projects. I
| certainly was one when I was in school.
|
| Static typing is a good choice when the system you are
| implementing is already defined. It's great for implementing a
| well-defined algorithm or protocol, or a well-studied domain like
| game engines or financial exchanges or rocket ships. Basically,
| wherever correctness is necessary and _possible_.
|
| Static typing is a _bad_ choice when the system you are
| implementing is largely undefined, or actively evolving. That is,
| "the rest" of the software, where "software correctness" is
| undefined. Which includes things like a business, a new video
| game, a website, and scientific research. Because you will waste
| time building an ontology of types that can't possibly be known
| at the time, or worse, constrain the natural evolution of the
| project.
|
| CS students often get a warped perspective of software, where
| everything is well-defined by their professor or some textbook or
| RFC or some other smart bloke, and they just have to implement
| it. In reality, the average software project is not this way.
|
| The end result is Enterprise Java (formerly C macro hell). You
| get a bunch of CS grads who think static typing is the only
| answer working on some fuzzy business logic with Java. The
| conclusion is an unspeakable monstrosity of bad abstractions (and
| job security).
| taeric wrote:
| Strong static typing, where most of your data is going across the
| wire as JSON, is a battle that is largely fought in incoherent
| ways.
|
| Yes, you should try and use all tools at your disposal. But you
| should also find that most "data" is far more squishy than you
| think it is. People don't fall back to phone numbers being
| strings because they are lazy, they do it because too many of
| them made the mistake of thinking they could make them a stronger
| type at some point. Same for names. Or addresses. Or postal
| codes. All of these things need to be taken from a user, and the
| only real way we have to do that is by parsing text. And if you
| make the mistake of making your system so it doesn't store the
| preparsed text, you are almost certainly going to regret it at
| some point.
|
| Now, is it best to have a layer that keeps the original user
| entered text and offers it as a typed set of data to the user in
| the backend? I certainly think so, but there will be ROI
| considerations as to how much that matters for your little part.
|
| More, if you are doing evaluations of any heavy sort, you
| probably want a translation layer to a SAT or other numerical
| model for calculation. And in that world, the numbers are the
| abstraction. Trying to do it another way will almost certainly
| lead to pain. And again, you will do well to have translations
| from problem to formulation, and from solution space to domain.
| All of these can largely be helped with types, but far too often
| the "types" that are focused on are not these.
| galdosdi wrote:
| > Strong static typing, where most of your data is going across
| the wire as JSON, is a battle that is largely fought in
| incoherent ways.
|
| Is it really? Map<String,String> is a totally reasonable type
| to use in certain cases.
| bluGill wrote:
| You should still use name and address as types not strings,
| even though when you look deep you discover they are both
| strings. It is [almost?] always an error to mix up name and
| address fields and the type system can enforce this.
| taeric wrote:
| This is why I said it will be an ROI of where you are. In
| your javascript just pulling the data out of form fields to
| send to the backend? Probably not worth it. Somewhere between
| taking it from the user and processing it? Probably worth it.
| And sending it to another system? You almost certainly need a
| translation between your types and theirs. But making a layer
| that converts between every one of your types to every
| possible external system? Probably not worth it.
| tasn wrote:
| Author here. One thing that we do at Svix that I alluded to in
| one paragraph but I should probably have elaborated on further:
| thanks to libraries like Serde and Pydantic, we actually follow
| deserialization is validation (is that a term?), which means
| that we validate all of the JSON data before even creating the
| structures in our code.
|
| I guess that's similar to the redis example I gave, but it
| essentially means that even though we get sent JSON over the
| wire, we validate it fully and when it gets to our code we know
| it's a well formatted type. So our code can assume an email
| type is a valid email, an ID type is a valid ID, etc.
| funnymony wrote:
| > deserialization is validation
|
| I saw similar, catchy phrase: "parse, don't validate".
|
| https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-
| va...
| taeric wrote:
| Right, but you should also take pains to keep the original.
| All too often the deserialization/validation can also alter
| the data. In many places, this is fine, I think. In many
| others, it leads to a ton of confusion.
|
| Edit: I wrote "but you should", I really should have worded
| that as "and you should". I am wanting to add to your point,
| not contradict it.
| tasn wrote:
| Oh yeah, I agree, and I learned it the hard way. In many
| cases you want to keep the customer format rather than the
| canonical format. This is why I stopped using Postgres's
| JSONB for customer data, and exclusively use String/JSON
| nowadays.
| williamdclt wrote:
| > deserialization is validation (is that a term?)
|
| "Parse, don't validate >> is a common Googleable idiom
| davedx wrote:
| It's absolutely a term, and the way to go
| AdamN wrote:
| What I like that you're doing and what I used to do with
| Python annotations is that you strongly define types for your
| higher level business logic - which may be encode quite
| complex formats.
|
| In many ways, your point is correct and kind of difficult to
| argue against (i.e. I agree!).
|
| What catches alot of people is they say how important types
| are but then just use 3 or 4 primitive types and never build
| custom types on top of them so they don't get much value out
| of those types aside from preventing the absolute worst
| runtime errors. The real value of types is having lots of
| them and evolving them over time as your systems and
| capabilities mature (US street address, US state, latitude,
| ... the list goes on for any piece of software).
| digging wrote:
| Huh! That's given me a lot of insight into why I've had to
| argue about typing in the past. Thanks for encapsulating
| that for me.
|
| I've had teammates "agree" and use types only to use the
| most basic possible types and then confuse themselves later
| (like, days later). But to me, because I _like_ static
| typing, it comes very naturally to define types based on
| business logic, which makes things very easy to work with.
| And they 're just not thinking in that way. Now I wonder
| how I can bring them around.
| manicennui wrote:
| This seems to be a common practice in Go and I've seen it
| cause requests to be rejected because one unimportant field
| is wrong. Were we to do this for truly important requests,
| like lead traffic from third parties, we would lose a lot of
| business.
| mcesch wrote:
| If the field is unimportant you'd represent it as such.
| `Option` or `Maybe` or whatever the equivalent wrapper is
| in your language of choice.
| cbdumas wrote:
| > we actually follow deserialization is validation (is that a
| term?)
|
| Perhaps you are thinking of this great blog post on the
| subject https://lexi-lambda.github.io/blog/2019/11/05/parse-
| don-t-va...
| lucasyvas wrote:
| This is correct - if it's going to error or panic, it should
| do it at the boundary, not at a random place in the program.
| It's also much faster to debug where the issue is this way.
| stratigos wrote:
| This article might be right in an academic sense. I suggest the
| author and those who believe similarly that its a "hill to die
| on" rethink their approach and spend 5-8 years doing professional
| consulting (do not confuse consulting with staff augmentation).
| You will indeed die on the hill as a business cannot expect
| everyone it hires to believe the same thing, and you cannot
| expect to force anyone to use strong typing properly. In short,
| while you may believe this is the right path, most folks dont
| care, and all that remains is an extremely complex,
| antipatterned, mysterious ball of mud that no one wants to work
| with because no one fully bought into the concept for which you
| were willing to die.
| cma256 wrote:
| Static typing won there's no point arguing over it anymore. The
| issue is the type systems. Someone writing Haskell will have a
| very different opinion of types versus someone writing Rust
| versus someone writing Typescript versus someone writing Bash.
|
| That's why you see a negative reaction to static typing. Its the
| developer experience. Its the error messages. Its the amount of
| time and mental effort it takes to type something correctly.
|
| If you told me I had to choose between dynamic Python or strict
| Typescript I would choose Python. I love static typing. I hate
| Typescript.
|
| So don't die on a hill! Just make better type systems!
| kmstout wrote:
| I want different things at different times. When I'm first
| exploring a problem space or figuring out an approach or fooling
| around in a REPL, dynamic typing is great. In those
| circumstances, the ability to quickly test (and reject!) ideas is
| critical, and I don't usually find static typing worth the
| friction. On the flip side, when I'm working on something longer
| lived or mission critical, it's important to set the maintenance
| brigade up for success. That means, among other things, useful
| doc strings; detailed and informative design notes; and type
| declarations with the right level of specificity.
|
| Of course, the coin has a thin edge where the situation is a bit
| of heads and a bit of tails. Count me a fan of gradual typing.
| mtreis86 wrote:
| What do you call the Common Lisp sort of typing where you can
| drop hints wherever the machine is guessing at the type, and it
| will yell at you if you do something dumb with those things. But
| you don't have to drop hints at all and it will still compile. It
| is strong when you turn it on but dynamic otherwise. Strongly
| typed with inference, maybe?
| Filligree wrote:
| Gradual typing?
| ctenb wrote:
| I believe the term is gradual typing?
| KaiserPro wrote:
| Personally I think Strong Static typing is what's required. But
| with an option to do dynamic typing to avoid faff in certain
| parts. Strong typing on its own doesn't really solve the problem
| that the author is describing.
|
| c# pretty much has that nailed. You can do dynamic typing if you
| want, but you're on your own if it fucks up. Moreover its obvious
| when you're doing dynamic silliness.
|
| Python is strongly typed, the problem is that its also duck typed
| and everything is dynamic. Sure there is type hinting, but that's
| mostly optional and pretty much broken as its not really
| supported at run time. (unless I've missed something)
|
| What I'd really like is something like perl's "use strict;" in
| python.
|
| however I don't see that coming anytime soon.
| purpleblue wrote:
| I did C/C++ for the first 15 years of my career. I generally
| agree that strong typing is better for everyone.
|
| But when I started working with python, I understood the beauty
| in it. At first I couldn't believe you could have a system
| running reliably that was being hit by millions of people around
| the world, but then that's when I fully appreciated the power of
| automated testing. I came from an enterprise shrinkwrap
| environment with 1.5 hr dev cycles, so you can forgive me for not
| understanding CD/CI at that point.
|
| Yes, you can't detect when changes could cause bugs, but that's
| where testing comes in. Where I worked, we had to have complete
| code coverage so that every line of code was tested, and we
| needed to have a very strong automated testing. Using that method
| of testing, it made it a lot more predictable.
|
| Sure, bugs can leak through, but having worked in C/C++ for so
| long, I can assure you that static typing only fixes a certain
| number of bugs, there are plenty more sources of bugs that just
| types.
|
| So for the record, I like static typing and generally agree with
| using it, but I also see the beauty and simplicity in dynamic
| typing like Python and it's not complete chaos and there are ways
| to mitigate it.
| mhandley wrote:
| I wish the languages I use would not only provide static strong
| typing, but also proper explicit support for units. Automated
| dimensional analysis would prevent many of the bugs I've written
| over the years, and there are so many times I've had to think
| carefully whether a variable is in seconds, milliseconds or
| microseconds to the point where I always define my own types of
| these. Or whether a throughput count is in Mbits/second or
| Bytes/second.
| globular-toast wrote:
| I wish people wouldn't conflate dynamic typing with weak typing.
| Python, for example, is dynamically typed, but it's _strongly_
| typed too. You don 't get bugs like `1 + "2" = "12"` in a
| strongly typed language like Python.
|
| You can still get runtime bugs, of course, but that kind of thing
| would manifest as a TypeError or something. All of those bugs
| could be caught with tests.
|
| I like dynamically typed languages. They are simply the pragmatic
| choice for the vast majority of code that will ever be written.
| But being dynamic doesn't mean you can't do types. Python has
| optional type hinting and checkers like mypy are very good.
| Common Lisp has features that enable you to declare types and get
| near-native speed binaries.
|
| These days I do type my Python code for many of the reasons given
| in the article, but I still enjoy using a dynamically typed
| language underneath.
| tonyedgecombe wrote:
| >You don't get bugs like `1 + "2" = "12"` in a strongly typed
| language like Python.
|
| That's more about type coercion which you can avoid in dynamic
| languages. See === vs == in JavaScript.
| sakex wrote:
| Not all type systems are born equal, for instance I'm amazed
| daily at the lack of type safety in Java/Kotlin
| mpweiher wrote:
| Well, people have always been fanatical about thing a they are
| attached to emotionally, rather than rationally.
|
| Fact is: the "types lead to fewer bugs" claim is just a feeling,
| it is "truthy".
|
| https://blog.metaobject.com/2014/06/the-safyness-of-static-t...
|
| And it's not for lack of trying. You might say the claim has been
| disproven.
|
| That said,I personally like static types, but primarily for the
| documentation effect that is, maybe not entirely coincidentally,
| the only positive effect for which there actually is solid
| empirical evidence.
| magicalhippo wrote:
| The fact that strong static types makes the code self-
| documenting is _the_ reason I vastly prefer it.
|
| It makes me _so much more productive_ , by orders of magnitude.
| And I say this as someone who has worked extensively in several
| different languages which covers large parts of this spectrum,
| like C, C++, Java, Python, JavaScript, TCL and others.
|
| It makes it much easier for me to reason about code I have not
| recently worked on, be it in the current project or in
| dependencies. It also means I can be way more focused on the
| problem at hand, since I'm not constantly having to go on
| tangent goose chases to figure out what exactly I can do with
| this object that some function returns.
|
| Sure there's the good, fuzzy feeling when the compile doesn't
| error out. But that's secondary.
| fnfjfk wrote:
| Academic papers are often very disconnected from industry
| reality.
|
| I've worked on reliability at a company everyone has heard of
| for software that billions use daily. So many bugs would have
| been blocked by having a type system at all (dynamic languages
| on backend or JS on web) or by having a less bad type system
| (changing ObjC to Swift and Java to Kt on mobile). Null
| pointers/references alone have created so many bugs for us.
| Bugs that could have been compiler errors.
| mrkeen wrote:
| > Well, people have always been fanatical about thing a they
| are attached to emotionally, rather than rationally.
|
| How would you feel if I claimed that you could make emotional
| arguments _faster_ than you could make rational arguments?
|
| Because that is how this debate _feels_!
|
| I want the simple rationality of my compiler saying "no" if I
| try to treat my hashmap like an Apple or a String.
| unstruktured wrote:
| The author of that link references the top 25 bugs, one (#12)
| of which is Null pointer dereferencing- static typing outright
| eliminates that bug.
|
| Not to mention that range checking is also fixable by using
| optionals rather than assuming the existence of a value.
| purpleblue wrote:
| It leads to fewer bugs of a certain type, but there are plenty
| of bugs being generated in statically typed languages in
| different ways.
| mpweiher wrote:
| The overall bug burden does not change.
|
| Why this is we do not know. But we do know that it is true.
| tomtheelder wrote:
| Research on this topic is beyond impossible and should be
| completely disregarded. You cannot possibly attempt to control
| for variables sufficiently, and I don't think even the most
| fervent supporters of type systems would argue that they are a
| dominant factor in code quality and correctness.
| Chabsff wrote:
| "Types lead to fewer bugs _when making changes to long-lived
| codebases_ " is not up for much of a debate in my opinion.
| Preventing regressions is arguably a lot more important than
| writing a correct first pass, which is what you are evaluating
| when looking at non-evolving code.
|
| Concretely-speaking, an example of a bug being preventd by a
| typing system: Removing a field from an object in a large
| vanilla JavaScript project is _inherently_ a minefield that has
| caused many bugs in the past, whereas the same alteration in a
| full Typescript project can be made with confidence.
| mpweiher wrote:
| It's no longer up for debate, true.
|
| But not in the way you fervently want to believe.
|
| Once again: people have tried to show the truth of this for a
| long time, and they have consistently failed.
| Chabsff wrote:
| I'm arguing that the studies linked in that blog post are
| fundamentally flawed because they only take into account
| first-pass development, and fail to take long-term
| maintainability into consideration. And this is silly
| because that's where the main value of type systems reside.
|
| > This paper presents an empirical study with 49 subjects
| that studies the impact of a static type system for the
| development of a parser over 27 hours working time.
| mpweiher wrote:
| That is not true.
|
| There are some studies like that, but there are others as
| well.
|
| And remember that all these studies were trying to find a
| positive effect, but failed to do so.
| Chabsff wrote:
| Well... It is true of everything in that blog post.
|
| But I am wiling to have my mind changed. I would be
| really interested in seeing a study that failed to find a
| benefit of type systems for refactoring tasks in large
| projects. The example I posted in my initial comment
| seems pretty open-and-shut to me, so I'm curious.
| mpweiher wrote:
| > Well... It is true of everything in that blog post.
|
| That turns out not to be the case.
|
| > I would be really interested in seeing a study that
| failed to find a benefit of type systems for refactoring
| tasks in large projects.
|
| You're inverting the burden of proof here. People who
| claim that something is beneficial are the ones who have
| to show that it is.
|
| Making a claim and then shouting "prove me wrong!" is not
| how science works. Not even computer science.
| spion wrote:
| https://www.bmj.com/content/363/bmj.k5094
| [deleted]
| boxed wrote:
| And yet, if the signal was that strong, it should be
| clear. It's not.
| taeric wrote:
| It... should be up for debate? I'm fine taking it as a given
| in projects I'm running. But I do expect people that have the
| ability to do so, to debate it. Preferably to study it and
| find concrete evidence.
| Chabsff wrote:
| Admittedly, that was a bit hyperbolic on my part.
|
| What I meant to convey is that the matter is settled enough
| from my point of view that there needs to be a very strong
| case being made for me to be willing to engage in that
| conversation.
|
| Thanks for pointing this out, I've amended the comment to
| clarify a bit.
| mpweiher wrote:
| > the matter is settled enough
|
| Based on what evidence?
|
| Apart from emotion?
| taeric wrote:
| Charity to the idea, when boots are on the ground to do
| the actual work is a terribly place for running that
| debate. :D Is why I'm in agreement enough for projects
| I'm working on. I am open to the idea that we find more
| evidence and/or change our minds for the next project,
| but "when in Rome" is a good reason to drop the debate
| and basically declaim what your driving idea is at the
| start.
| nurple wrote:
| "Types let me make changes to code I haven't taken the time
| to understand" is hardly the proof you seem to think it it's.
|
| Removing a field in a data structure is such a big problem,
| even in typed systems, that the most ubiquitous serialization
| IDLs, and customer-facing API conventions, don't even allow
| it.
| Chabsff wrote:
| And I would contend that anyone claiming "I am capable of
| taking everything about the code I am tasked to change into
| consideration" is delusional when it comes to non-trivial
| projects, including single-dev endeavors.
|
| As far as serialization IDLs and API conventions go, they
| have the very special constraint of having to provide both
| forward and backwards compatibility across multiple
| applications, making them a very poor universal example.
| mpweiher wrote:
| Is there anyone making that claim? Apart from straw-men?
|
| As an example, I was once refactoring a Java system. The
| compiler was happy after about a day, the unit tests
| after three days.
|
| So if you claim your type system is going to keep your
| refactoring safe, I'd say that I'm not the one being
| delusional.
|
| And of course unit tests also tend to, _in practice_ ,
| catch the errors that are caught by types. If you check
| that a value is equal to 10 rather than 9, you've also
| implicitly checked that it is not of type PinkElephant.
|
| Now I perfectly understand the _feeling_ that people who
| are used to the safety-net that static typing appears to
| give have when encountering a code-base without types. I
| have the same _feeling_ when encountering a code-base
| without reasonably comprehensive unit tests (that fail
| when I poke into the code-base).
|
| The feeling is absolute terror.
|
| I just contend, with reasonably good justification, that
| this feeling is not particularly justified in the case of
| static types, because the evidence is just not there.
|
| I haven't checked what the evidentiary status is for unit
| tests. But then again, I don't make these sorts of
| categorical claims for unit tests. I just make claims for
| _my experience_ with unit tests.
| Chabsff wrote:
| > Is there anyone making that claim? Apart from straw-
| men?
|
| For every intent and purpose, the person I'm replying to
| is, with an equivalent level of straw-man-ness, which is
| why I phrased it this way.
|
| > So if you claim your type system is going to keep your
| refactoring safe, I'd say that I'm not the one being
| delusional.
|
| No, I'm claiming that there are entire categories of bugs
| that are protected this way, not that it provides
| universal safety.
|
| > And of course unit tests also tend to, in practice,
| catch the errors that are caught by types. If you check
| that a value is equal to 10 rather than 9, you've also
| implicitly checked that it is not of type PinkElephant.
|
| It provides that if and only if the code invoking the
| tested function is called with arguments using the same
| semantics as the ones exercised in the tests, which is
| impossible to enforce in a dynamic language. I'd even go
| so far as saying that it is axiomatically impossible for
| unit testing to be a truly reliable tool in such
| languages because of the lack of precondition
| enforcement.
| mpweiher wrote:
| > the person I'm replying to is [making that claim]
|
| Er, no. I certainly wasn't, and the person you were
| replying to above that was making the opposite claim:
| that it's harder than that.
|
| And no, the type system doesn't really help all that
| much, once you have unit tests. Because unlike the unit
| tests, which checks values (and obviously the types as
| well, incidentally) the type system only checks the
| types.
|
| So, trivially, if you mix up addition and subtraction,
| your unit tests will rightfully balk, whereas your type
| system is going to be "works for me".
|
| As I wrote elsewhere in this thread, in my personal
| experience the type system was happy during a large
| refactor long before the unit tests were. Which means
| that there was a lot of stuff that the type system
| missed.
|
| And so if you feel your type system is going to make your
| refactors safe, well, good luck to you and the poor
| people who have to use your code.
| Chabsff wrote:
| To address the unit test stuff: I'm not saying that type
| systems replace unit tests. I'm saying that unit testing
| in dynamically typed languages is fundamentally
| deficient. Or in other words: unit tests are made more
| reliable by type systems.
|
| Unit tests can only check outputs for the inputs that are
| provided during testing. Leaving the input unbounded
| means that they can only provide guarantees for code that
| conforms to the tested subset of inputs.
|
| I may be able to test that `foo(3) == 4` and foo("foo")
| == "bar", but since I can't guarantee that `foo({})`, or
| literally anything else, will never be called, there will
| always be holes in the safety net they provide. This is
| something type systems _directly_ address.
|
| > And so if you feel your type system is going to make
| your refactors safe, well, good luck to you and the poor
| people who have to use your code.
|
| safer. It makes them safer, not automatically safe.
| spion wrote:
| I often rename a field in a typed language, just as a way
| to ask the compiler which parts of the code are affected by
| or use that field then I continue my reading there.
|
| Its like a grep, except it can, for example, differentiate
| between "name" (of user) and "name" (of project)
| nercury wrote:
| The argument for static types is that it makes type bugs
| impossible because the types are static. There is no emotional
| attachment other than rage when faced with "but but it does not
| eliminate ALL the bugs!!!!!!".
| mpweiher wrote:
| Please read the article.
|
| The objection is not that all bugs aren't eliminated. The
| objection is that there is no empirical reduction in bugs.
| miloignis wrote:
| You're making a very strong statement, so we might as well look
| at extreme cases, namely the formally verified middle-end of
| CompCert:
| https://users.cs.utah.edu/~regehr/papers/pldi11-preprint.pdf
|
| I believe this would count as empirical evidence of very strong
| static typing reducing bugs. I think this points to what many
| other comments have been getting at, which is that typing is
| not a binary yes/no question, but a large, multi-axis
| (static/dynamic, strong/weak) spectrum with lots difference
| between type systems, _as well as_ big differences in how
| people apply those type systems to their problem. You could
| still work in a static, strongly typed language and represent
| everything as strings, converting back and forth as necessary,
| but that 's essentially working in a dynamically typed
| language. You could also take advantage of the tools the type
| system gives you in order to reap the benefits, creating
| classes representing the legal values and asserting important
| invariants.
| iopq wrote:
| Heartbleed is not a type error in C, but it's a type error in
| Rust
|
| Rust has a more powerful type system that actually fixes MOST
| of the memory bugs in production
| mpweiher wrote:
| And you simply can't have that sort of error in Smalltalk.
|
| -\\_(tsu)_/-
| jjnoakes wrote:
| You absolutely can.
| mpweiher wrote:
| That turns out not to be the case.
|
| Smalltalk is memory safe and dynamically type-safe. That
| is, you cannot invoke an inappropriate operation. You can
| _try_ to do that, but the system will refuse to do so.
| jjnoakes wrote:
| It's trivial to store sensitive data in a collection, for
| example, and then index it with the wrong index when
| trying to access and export adjacent non-sensitive data.
| shafo wrote:
| https://youtu.be/Xb0UhDeHzBM
| j16sdiz wrote:
| I think clojure spec is still typed. It is just not the type
| other languages uses.
| nightwolf wrote:
| clojure.spec is explicitly not a type system:
|
| https://clojure.org/about/spec#_expressivity_proof
| xeckr wrote:
| I gave TypeScript a shot on more than one occasion, and it always
| ended in frustration after I inevitably encounter some obscure
| ts(42069) error that I have to research, then find out that a
| compiler bug is causing the error, and then get told "it's fine,
| just add @ts-ignore to the top of the file! See, your code works
| now!"
| [deleted]
| nurple wrote:
| The social pressure to love static typing notwithstanding (think
| less of me if you will), the reason I got turned off by it
| eventually are the ivory towers that invariably get built up
| around them. I've spent a decade each building software in both
| paradigms and I now prefer not to use type systems.
|
| I find dynamic typing similar to how unit testing is a forcing
| function for writing composable code, it acts as a forcing
| function to writing simple code; simple to read and simple to
| comprehend.
|
| The argument that it helps inexperienced developers approach the
| codebase is, IMO, a poor one as it tends to incentivize an
| iteration loop that lacks understanding and is simply trying to
| make all the red go away. In fact I find that the type system is
| often a barrier to truly understanding what's going on as it
| effectively adds a very domain specific language to every project
| that has to be learned on top of the language itself.
|
| There are methods to solving the problems presented in TFA that
| are just as robust as using types and which are simple to
| understand. Can types be used in a simple way? Sure. Are they
| ever? Not in my experience. I also don't like autocomplete, so
| take that as you will.
|
| I may just be a grizzled greybeard screaming "the code _is_ the
| documentation", but perhaps that is born from my deep
| dissatisfaction with the current breed of get-big-paycheck-
| chatgpt-said-it's-right devs that are currently flooding the
| industry.
| [deleted]
| spankalee wrote:
| I really don't understand these lines of argument, because they
| seem to me to be almost entirely _backwards_.
|
| > I find dynamic typing ... acts as a forcing function to
| writing simple code; simple to read and simple to comprehend.
|
| I find the opposite true. Many super-dynamic patterns are hard
| to type correctly. Good type systems tend to encourage simpler
| patters so you get simpler types.
|
| > The argument that it helps inexperienced developers approach
| the codebase is, IMO, a poor one as it tends to incentivize an
| iteration loop that lacks understanding and is simply trying to
| make all the red go away.
|
| Making the red go away is important because the red indicates a
| problem! This is a lot easier than other ways of discovering
| the error. Why would you want to discover the error later?
|
| > I also don't like autocomplete, so take that as you will.
|
| This is why I'm with commenters who say they don't trust people
| who are against static typing... I'm extremely suspect of
| computer programmers who don't want computers to help them
| program.
| zsyllepsis wrote:
| > Making the red go away is important because the red
| indicates a problem! This is a lot easier than other ways of
| discovering the error. Why would you want to discover the
| error later?
|
| I don't think that's what the parent to your comment is
| arguing. They are arguing that "making the red go away" isn't
| the goal, rather that correctness is, and that it's easy to
| conflate the too when you focus too much on the "red" part,
| and don't pay attention to the "correct" part.
|
| Worded another way, the mantra of "if it compiles it works"
| can lead to a dangerous false sense of security if you don't
| understand the limitations of your type system and what parts
| of your program is may or may not cover completely.
| koonsolo wrote:
| > I also don't like autocomplete
|
| You must have a crazy good memory. I switch between multiple
| languages, and autocomplete lets me easily see what variant of
| a function this library uses again.
|
| You know everything by heart?
| imran-iq wrote:
| I also don't like autocomplete. The reason being that not
| having it actually forces me to learn the libraries I am
| using.
|
| > You know everything by heart?
|
| You eventually reach that point. Do you still look down to
| see which keys you are typing?
|
| This is also has the nice side effect of pushing you to use
| libraries that are stable and have good documentation as you
| can always reference them if need be.
| [deleted]
| lsaferite wrote:
| My working memory has limits. I consume and use a lot of
| information on an ongoing basis. The contextual shift from
| codebase to codebase is already large, add in a language
| change and I would venture to say that most people need a
| little assistance to make sure they remember syntax and
| specific method calls.
| koonsolo wrote:
| My memory is a leaking bucket. My typing however, is very
| fast.
|
| Take for example the substring function. I wouldn't know
| which one it is for JavaScript, Haxe, ActionScript3, C#,
| Java, Python, C, C++, PHP. I know I used it at one point
| for all of them.
|
| For languages like JavaScript, Java and C#, it's probably a
| method, so you can start typing. Might be substring(),
| might also be substr() or something like that.
|
| For Haxe, I thought it was not a method so I think it's
| either part of Std or StringTools.
|
| If I use autocomplete, I have it in a few seconds, and I
| can also see the documentation on the parameters. Is the
| second parameter an index or a length? To be honest I have
| no idea. And the good part is, thanks to autocomplete I
| don't need to know.
|
| Also, if you work in a big codebase, you can't know every
| class. Needing to dig through code seems such a waste of
| time.
| leptons wrote:
| I also hate autocomplete. It just gets in my way.
| Autocomplete doesn't really work unless you already know what
| you're going to code, and if you already know what you're
| going to write the autocomplete prompt just gets in the way
| and often messes with keyboard entry of what I was typing. I
| just switch it off, it never saved me any time and just gets
| kind of annoying.
| spankalee wrote:
| > Autocomplete doesn't really work unless you already know
| what you're going to code
|
| Say what? Autocomplete is a godsend for quickly working
| with new APIs. If you're writing a function that takes some
| objects that you're not familiar with autocomplete can
| pretty quickly lead you down a good path.
| leptons wrote:
| That's not my experience. If I'm working with new APIs, I
| have the docs up on one screen and the code on the other,
| and I've probably already copied and pasted the function
| and parameters into my code from the docs before
| autocomplete can get in my way. You do read the docs,
| don't you?
| tasn wrote:
| I think you make a good point about the ivory towers and the
| social pressure being a turnoff for adopting certain
| technologies. Though I also think this doesn't detract from
| their potential technical merits. As in, a technology can be
| both great, and have everyone about it be pretentious.
|
| > I find dynamic typing similar to how unit testing is a
| forcing function for writing composable code, it acts as a
| forcing function to writing simple code; simple to read and
| simple to comprehend.
|
| I don't agree with this argument, I think it's akin to saying
| "I like driving blindfold because it makes me drive slower".
| You can use linters with limits on line length and number of
| params if this is a goal for you, no need to go indirect with
| the restrictions.
|
| I agree that typing is not the only solution, I'm just saying
| that I think the ROI is massive in types, so I think this
| should be the first tool people go to. Almost no investment,
| and a lot of benefit.
|
| I agree with "code is the documentation", I even made a point
| about documentation in the post, but I argue that typing is
| part of the code. So "the code is the documentation, and typing
| is part of the code" is how I'd phrase it.
| sodapopcan wrote:
| > > I find dynamic typing similar to how unit testing is a
| forcing function for writing composable code, it acts as a
| forcing function to writing simple code; simple to read and
| simple to comprehend.
|
| > I don't agree with this argument, I think it's akin to
| saying "I like driving blindfold because it makes me drive
| slower". You can use linters with limits on line length and
| number of params if this is a goal for you, no need to go
| indirect with the restrictions.
|
| I was assuming this is more along the lines of writing clear
| variables names and writing functions that make it obvious
| what the return value is.
| eyelidlessness wrote:
| > I find dynamic typing similar to how unit testing is a
| forcing function for writing composable code, it acts as a
| forcing function to writing simple code; simple to read and
| simple to comprehend.
|
| If this were broadly true for most developers using dynamically
| typed languages, it would be a very compelling argument indeed.
| But I think there's pretty strong evidence the opposite is
| generally true: actual types produced to document real world
| dynamic code tend to be vastly more complex than the equivalent
| functionality implemented with static types from the outset. In
| the TypeScript ecosystem, DefinitelyTyped is an excellent
| source of countless case studies. The types they provide are
| typically _definitely not_ , as you put it, "used in a simple
| way". That's not complexity inherent to the type system, or the
| type definitions as provided; it's complexity inherent to the
| dynamic code they describe.
|
| Equivalent packages which were statically typed from the outset
| tend to have much simpler interfaces _because_ the types are
| defined upfront rather than retconned onto existing APIs. That
| doesn't necessarily mean their interfaces are _absolutely
| simple_ , but they're typically _relatively simple_ by
| comparison.
|
| I'd go so far as to say that you _can't know_ how simple or
| complex an interface is without specifying it. If "the code is
| the documentation" (which I agree is a great ideal!), then
| interfaces without code specifying them are under-documented by
| definition. The further the code specifying the interface is
| from the interface itself, the more obscured your documentation
| is.
| hparadiz wrote:
| Dynamically typed language have very clear rules. It's not
| magic. If you know these rules nothing about dynamically
| typed code is inherently problematic. It's the difference
| between logic being in the code versus in the run time. You
| accept hundreds of rule sets built into the run time all the
| time.
| MrJohz wrote:
| All programming languages - all computers even - have very
| clear rules. The complexity in software development usually
| has less to do with getting a computer to understand its
| own rules, and more to do with the boundaries between
| humans and those rules: for example, encoding human ideas
| into rigid computer rules, or trying as a human to
| understand the computer rules that someone else has
| written.
|
| So when you say "if you know these rules nothing about
| dynamically typed code is inherently problematic", my
| intuition says "I probably don't know these rules". That
| goes for some of the basic rules like "the first argument
| to this function is the haystack, the second is the
| needle", but it also goes from some of the more complex
| rules like "functions that take a user ID can also take a
| user object and extract the ID from that" or "the allowed
| states for this FSM are X, Y, and Z, and are always written
| in capital letters". More importantly, a lot of the rules
| for my difference will not have been written by me, they'll
| have been written by my colleagues, or else they were
| written by me, but it was more than six months ago and my
| memory is a bit hazy on the details.
|
| The point the previous poster was making, I think, was that
| while the rules may be very explicit (this is, after all,
| what any programming language is: explicit rules for a
| computer to follow), they can also be very complex. And,
| more specifically, the DefinitelyTyped examples show that
| the rules for dynamic software often tend to be very
| complex, or at least, complex enough to present
| difficulties when being modelled by a type system
| explicitly designed to model dynamic code.
| digging wrote:
| > The argument that it helps inexperienced developers approach
| the codebase is, IMO, a poor one as it tends to incentivize an
| iteration loop that lacks understanding and is simply trying to
| make all the red go away. In fact I find that the type system
| is often a barrier to truly understanding what's going on as it
| effectively adds a very domain specific language to every
| project that has to be learned on top of the language itself.
|
| This is very interesting and at first blush strikes me as
| backward. I wish I could sit in your office and see this
| happening, because I find it hard to imagine and I would love
| to know what that looks like. (And I have way less experience
| than you so I'm not saying it can't happen.)
|
| Specifically, I find the domain-specific logic in my field is
| impossible to grok in dynamically typed codebases, while
| statically typed ones actually teach the developer what the
| business logic is.
|
| > I may just be a grizzled greybeard screaming "the code _is_
| the documentation"
|
| Also confusing to me! In all my experience, static typing is
| what allows the code to be the documentation. Without it,
| there's no way to know what properties this object has or why
| we have a check for this certain property that I thought didn't
| even exist on this object. (Other than comments - maybe I'm on
| a weird team but I don't know anyone other than me who leaves
| comments of any significance.)
| spankalee wrote:
| Comments are great, but they should usually explain why, not
| what.
|
| Good, long variable and function names, along with breaking
| complex expressions into multiple statements with those nice
| variables names can help the code itself describe the what of
| the process. And then static types help describe the what of
| the types of data even more.
|
| That lets you save the comments for more useful things than
| an ad-hoc type system, like "// We need to do this
| because..."
| hparadiz wrote:
| Code coverage reports with complexity score for every
| function is the best teacher for this. I particularly love
| how Scrutinizer CI does this.
| graypegg wrote:
| The social pressure side, I totally get. People get very
| defensive about this sort of thing, and act somehow personally
| offended if anyone does the opposite.
|
| I say that as someone that quite likes static types. I don't
| care, do what you do!
| ransom1538 wrote:
| When I hit ctrl+save, the code should be instantly ready to
| test, less than 200ms. Waiting for 30 seconds to see code is an
| ETERNITY to people that code fast, 1k lines per day. I have
| been on teams that wait 5m to test code, what a waste. Fast
| feedback loops in code are critical, just like design, or
| anything important. Types seem like some weird religion, the
| people that use them cannot be talked out of it.
| splintercell wrote:
| I highly recommend you to check out ReScript. Amazingly fast
| compile times.
|
| Watching typescript teams spent 30 seconds on the recompile
| is insane for me.
|
| in fact, the whole ocaml family of programming languages are
| mega fast.
|
| The most important feature of a very fast compile time is
| that you can load it with types after types and write in your
| whole mental model, without worrying about your build process
| slowing down.
| Djeman wrote:
| Code can not be documentation by meer definition. Code is
| written in programming language and documentation in spoken
| language. So documentation has important function of explaining
| intention of code in non trivial sections. Of course you wont
| give explanation of CRUD actions or other patterns you are
| using but business rules get coded and people reading that code
| need to know where rules come from and what are expectations
| either directly in code or by reference. Otherwise you revert
| to finding origin of code in source control and related task if
| you are lucky to have that level of tracking.
| busterarm wrote:
| I was going to write a response pretty much exactly like yours.
|
| Also, the domain we're in is engineering. There are no single
| correct decisions and everything is about trade-offs. And
| that's good because otherwise our jobs would be the first to be
| automated out of existence. All of the discussion in this
| thread about people "thinking less of" other engineers for
| their opinions/experiences is fucking gross.
| purplerabbit wrote:
| Your bio says "most people are stupid" -- how'd you arrive at
| that conclusion without judging people?
| busterarm wrote:
| There's a chasm of difference between blatantly self-
| destructive life choices and forgetting that your
| profession is about making decisions based on multiple
| options.
|
| Also you only half-quoted me.
|
| It's "... and/or on drugs".
|
| Also people being stupid doesn't mean that I don't consider
| anything they say. Even a broken clock is right twice a
| day.
| enraged_camel wrote:
| >> Also, the domain we're in is engineering. There are no
| single correct decisions and everything is about trade-offs.
|
| Yep. In my experience, hardliners tend to not be great
| engineers, even if they have decades of experience.
| JohnBooty wrote:
| hardliners tend to not be great engineers
|
| 100% agree.
|
| "Strong opinions, weakly held" is okay with me though. I
| don't call that "hardlining."
|
| Although, sometimes it's hard to differentiate "strong
| opinions, weakly held" from "strong opinions, strongly
| held, not open to new ideas."
| danenania wrote:
| I'm fully a convert to static typing and don't think I'll ever
| willingly do another project without it, but you make a really
| good point about how people tend to _always_ go overboard with
| types. I did this early on in a large TypeScript codebase while
| learning TypeScript, and now I regret it. I 'm still far better
| off than I'd be without static types though.
|
| This also happens with tests. It's easy to get wrapped in
| testing libraries and abstractions and spend way more time than
| you need to.
|
| The 80/20 rule applies in both areas. You get 80% of the
| benefit with 20% of the abstraction. It's usually a mistake to
| try to go beyond this.
|
| Of any popular language I'm familiar with, I'd say Go is the
| one that follows the 80/20 rule best. It encourages you to
| focus on solving the problem rather than leading you down
| rabbit holes of various kinds, including with types. That's not
| to say Go doesn't have its issues, but it really is excellent
| at discouraging over-engineering.
| thegeekpirate wrote:
| Heh, before reaching your last paragraph, I was going to
| recommend Go as the remedy to your woes. Glad you've
| discovered it yourself!
| QuadrupleA wrote:
| As a developer who's written hundreds of thousands of lines of
| C++, Python, and JS - I don't know! It's not so clear cut. I'm
| productive in all off them, although Python mostly wins. I
| wouldn't write a game engine or a video codec with it though.
|
| JavaScript is inconsistent and weird, but Netscape's legacy long
| since stuck us all into it.
|
| I can see in a very OOP-heavy style maybe, with huge nested
| classes, that compile/parse time static typing saves a lot of
| mistakes - but I've come to see OOP as mostly a disaster, and
| simple functions and structured data almost always win the
| simplicity and maintainability battle. And modern language
| servers / IDEs can catch a lot of typing errors during JS /
| Python development.
|
| I'm persnickety about a lot of programming stuff, but never had a
| strong opinion about static vs dynamic typing. Both have millions
| of successful projects under their belt.
| rdedev wrote:
| In python I mostly code in functional style. Even then types
| helps me a lot. I make a lot of typos or get the order of
| arguments wrong. Typing helps me a lot here especially when I'm
| doing ML. The last thing I want is my training code to crash
| after it spent 30nmins processing the data. I find pythons
| gradual typing a really good middle ground for quick
| prototyping and the type annotate functions once they are
| mature enough
| boxed wrote:
| > or get the order of arguments wrong
|
| There's a simple fix for that, just do keyword argument only
| everywhere you can.
|
| For me the hill I'm willing to die on is that
| labeled/named/keyword arguments are absolutely necessary and
| most of the usefulness of types is in fact just a shitty
| version of labeled arguments (god help you if you have a
| function where two or more arguments have the same type!)
| rdedev wrote:
| The small downside to using kwargs is just the extra
| letters needed to call the function but I can live with
| that.
|
| As for args with the same type, you can use phantom types I
| guess but I haven't explored it much in python. I'm pretty
| interested in the dfdx library in rust which can type
| enforce matrix or vector operations on it's shape. Stuff
| like that would really help me
| boxed wrote:
| It's an advantage imo. Makes the code more readable, and
| much more robust against bad refactors.
| BobbyJo wrote:
| To be fair, C++ is a pretty rough language to be productive in
| generally, type system aside. GC is the single largest
| productivity enhancement a language can offer. I'd be way more
| interested in how Golang, with it's much simpler syntax/types
| (but they're still static) would compare. Even Java would be
| better, as, even though it's very verbose, the cognitive load
| for most tasks is a fraction of C++'s.
| kagakuninja wrote:
| My language evolution went C > C++ > Java > Scala
|
| Java was a huge boost, by eliminating the cognitive load of
| manual memory management.
|
| Scala can be used as a "better Java" with less verbosity, but
| also adds a number of extremely useful features; Java has
| slowly added some of them into the language over the last 8
| years.
| sureglymop wrote:
| Have you tried Kotlin? I personally like it a lot as an
| alternative to Java and Scala. However, I hate any tooling
| around the JVM based languages. I cannot waste my time
| messing around with Maven, Gradle, etc.
| kagakuninja wrote:
| No, I am very happy with Scala, and intend to use it for
| many years to come.
|
| JVM tooling IMO is fantastic, it is one of the largest
| open source communities, and there are many options if
| you don't like Gradle or Maven. Also, as I understand it,
| the dependency management systems found in languages like
| Python and Node are horrible in comparison to the JVM,
| where it is usually not a problem.
| AdamN wrote:
| You might like this video from WWDC a few years back on
| protocol-oriented programming (Swift):
| https://www.youtube.com/watch?v=p3zo4ptMBiQ
| Draiken wrote:
| The only thing that really frustrates me in this discussion is
| that it's all about how people "feel" and without empiric
| evidence.
|
| The research out there found no meaningful difference between
| both styles (unless there's newer research I haven't seen?) and
| people keep taunting around how their preferred side is
| undoubtedly the right one.
|
| That's just like, your opinion man.
|
| Personally I like typed languages but the type systems in
| languages like TypeScript are simply insufficient. You still end
| up with runtime bugs because you can't actually use those types
| at runtime. You can't encode a lot of the runtime logic into the
| type system so you're still manually checking impossibilities
| everywhere. I find myself even having to create local variables
| just to make typescript detect an obvious condition.
|
| If a type system could basically remove the need for me to think
| about runtime bugs, then that's an absolute killer feature that I
| doubt anyone would argue against. But most languages don't
| provide that, so you're stuck in this halfway point where you
| have all this overhead, some benefits, but you still can't 100%
| trust your types.
|
| As for why there are no meaningful differences in bugs, speed,
| etc my guess is that it all evens out. Without the type system
| safety net you are much more likely to test your code and as a
| result less bugs go in. On the other side people rely too much on
| the type system that's not good enough and then still end up with
| the same amount of runtime bugs. On one side you write code
| faster, but you have to test more, so it also evens out with
| writing more boilerplate, but with less tests.
|
| I really wanted some hard research on this, but I know it's a
| hard one.
| ryandv wrote:
| A 2018 study [0] found the following:
|
| > Language design does have a significant, but modest effect on
| software quality. Most notably, it does appear that disallowing
| type confusion is modestly better than allowing it, and among
| functional languages, static typing is also somewhat better
| than dynamic typing. We also find that functional languages are
| somewhat better than procedural languages.
|
| > The languages with the strongest positive coefficients -
| meaning associated with a greater number of defect fixes are
| C++, C, and Objective-C, also PHP and Python. On the other
| hand, Clojure, Haskell, Ruby and Scala all have significant
| negative coefficients implying that these languages are less
| likely than average to result in defect fixing commits.
|
| > The data indicates that functional languages are better than
| procedural languages; it suggests that disallowing implicit
| type conversion is better than allowing it; that static typing
| is better than dynamic; and that managed memory usage is better
| than unmanaged.
|
| Regarding your comments:
|
| > Personally I like typed languages but the type systems in
| languages like TypeScript are simply insufficient. You still
| end up with runtime bugs because you can't actually use those
| types at runtime.
|
| That's because TypeScript is not actually strongly typed, it is
| gradually typed; throw in a single "any" type into your TS and
| all static guarantees are now off. I agree that TypeScript is
| insufficient, and point to languages like Rust or Haskell (one
| of the languages with the lowest defect rate in the study [0])
| that actually do offer static guarantees, and where use of
| untyped "escape hatches" is far less common and/or is far more
| judiciously applied.
|
| > If a type system could basically remove the need for me to
| think about runtime bugs, then that's an absolute killer
| feature that I doubt anyone would argue against. But most
| languages don't provide that
|
| Isn't this basically the promise of Haskell, Rust, et al? "If
| it compiles, it works;" "guaranteed memory safety," etc?
|
| [0]
| https://developers.slashdot.org/story/18/01/01/0242218/which...
| dang wrote:
| That study dates from 2014 and was discussed here:
|
| _A Large-Scale Study of Programming Languages and Code
| Quality in GitHub (2014)_ -
| https://news.ycombinator.com/item?id=15378800 - Oct 2017 (66
| comments)
|
| It's also discussed prominently in Dan Luu's survey, linked
| to here:
|
| https://news.ycombinator.com/item?id=37770719
| Hermitian909 wrote:
| > I really wanted some hard research on this, but I know it's a
| hard one.
|
| I think we'll have to settle for judgment calls.
|
| I tried going through some of the research we have on developer
| productivity a few years back and it's almost all garbage or is
| only truly applicable to juniors (e.g. when you're new you
| _really_ benefit from quick feedback time on static errors).
|
| The entire space suffers from the fact that good experimental
| design is impossible to implement with anyone who's not a
| college student (good luck getting professionals to follow your
| rules for months) and the curse of dimensionality from the need
| to disentangle individual variations, type of software
| development, management style, and a thousand other things to
| try and draw out a signal.
|
| Sadly, many things and life can't be effectively measured.
| d0mine wrote:
| It looks like you think writing your program in the language
| used to express types will magically remove "runtime bugs"
|
| If the language is powerful enough to be able to write ordinary
| programs, it is powerful enough to produce bugs.
|
| Static typing can be effective at catching certain types of
| bug, not all. It can improve readability sometimes (as a DSL
| for static unit tests/executable docs).
|
| In general, dynamic languages are more agile and you can write
| more tests easier. Some of the tests you wouldn't need to write
| in a statically typed language, therefore typing is still
| useful though not as universally effective as one might
| believe.
| patrickthebold wrote:
| Perhaps the issue is how people like to solve problems. I'm a
| huge typescript fan, and I say a lot of the hard work is
| designing the types. Then the code becomes 'the only thing that
| makes sense given the types'. There may be some duality at
| play, where otherwise designing the code is the hard work. And
| the types become, 'anything that makes sense given the code'
|
| And note the switch from 'only' to 'any'.
|
| Anyway just hypothesising.
| Draiken wrote:
| I had to learn TS because that's the hype today, and went
| into it after seeing some amazing F# talks on typing. I was
| amazed at the way they used types to ensure your code was
| actually correct. I was excited to be able to do that with
| TS.
|
| Then I found out the hard way that none of that works.
| Basically it's all a lie. You can't use the types in runtime
| so all that effort you put into the types doesn't actually
| translate when you want to use the type system to full
| effect. That was absolutely demoralizing.
|
| For me, the white elephant in the room is that the language
| doesn't really matter all that much. Good developers will
| write good code and bad developers will write bad code.
|
| Good developers might use meaningful types and bad developers
| will use strings, records and numbers everywhere.
| Guaranteeing a string is passed and not a number is not gonna
| prevent many bugs. Guaranteeing a `PhoneNumber` is passed can
| truly prevent bugs. But that's never the code that you
| actually see in the wild (even in the article).
|
| In the real world, most people can't even use half the type
| system they claim is so great.
| dgb23 wrote:
| Exactly my thoughts!
|
| The article and many commenters here all talk about programmer
| ergonomics, productivity and "correctness".
|
| The current research shows that these things are neither
| improved nor weakened by static typing. There are (even recent)
| papers on comparing typed vs dynamic language with no
| meaningful results. So basically it's entirely subjective.
|
| However there _is_ an actual effect of static typing that can
| be trivially proven: It enables a programmer to write more
| efficient code. That should be at the forefront of every
| discussion around typing discipline, because everything else is
| just _hot air_ at this point.
|
| TypeScript (used in the article) is an example that is _not_
| actually strongly typed (it's statically typed but weak) and it
| doesn't even provide performance and memory layout guarantees,
| because the types are just comments. So you pay all of the cost
| of static typing without _any_ of the tangible benefits except
| documentation.
|
| To me it is surprising that we as a technical community
| completely ignore actual evidence and take our cultural and
| personal preferences as fact.
| tasn wrote:
| I think most people would agree that types prevent a lot of
| bugs (and others posted research to support it in the thread),
| so the question is less about that and more about the
| subjective reasoning people have to decide the investment is
| not worth it.
| Draiken wrote:
| >I think most people would agree that types prevent a lot of
| bugs
|
| Again, that's not what research shows. Type checking bugs are
| most definitely not the most common ones and typing doesn't
| really help with runtime bugs unless it's a strongly typed
| language.
|
| I'm all for types, but after using TypeScript and seeing
| everyone (including the article) touting it as the solution,
| it simply isn't all that better than vanilla JS.
|
| I did spend countless hours having to wrangle typescript when
| integrating with third party libraries, searching for types
| that were not always there, manually extending/creating
| library types and so on.
|
| So no, it's not as clear cut as some say it is.
|
| If we want to argue for types, then we should use strongly
| typed languages that prevent these bugs (if you can manage to
| create the right types, of course). Examples in TypeScript
| are simply not going to cut it because that's a horrible
| example of a typed language. I mean, it's not even a
| language.
|
| Edit: above all, hard research. If there's research for this,
| why isn't that in the article?
| chrisco255 wrote:
| > Type checking bugs are most definitely not the most
| common ones and typing doesn't really help with runtime
| bugs unless it's a strongly typed language.
|
| TypeScript actually performed quite well in the last
| academic study I read on this debate (like 6 years ago).
|
| The real problem with web APIs is that there is always some
| lossy conversion between type systems as we cross
| boundaries. So we can't really make some sort of closed
| system assumption. A typical web app may interact with
| dozens of API services, some run by third parties. And
| maybe you can trust their API docs, but maybe not really,
| and they're subject to updates anyways, so you always have
| to be on your toes.
|
| Even internally, you can't really control all the type info
| from end to end. Even the most monolithic systems will have
| some sort of abstraction leak when going from JSON ->
| Object -> Relational storage. Even largely monolithic
| systems will typically break off some functionality (like
| email sending, websockets handling, etc) as a separate
| service. The boundary creates a co-evolving connection
| between separate services run by separate teams, with
| separate upgrade cycles, even without full microservices
| buy in. And that creates potential runtime type errors when
| mapping between these layers.
|
| Even if you've somehow plugged all those leaky abstractions
| and your tight type system has handled all the edge cases
| and is provably correct: the user will teach you otherwise
| on the UI layer. User input can vary wildly, and everything
| from device capabilities to personal disabilities to
| network throttling to authentication to using weird ISO
| characters to file sizes to strange input devices and
| legacy systems with their own quirks, will completely throw
| you off at some point.
|
| So no matter how type safe your language is, you'll always
| have to deal with the untyped and unpredictable user layer.
| And the reason why JS has been so successful there is
| because of how flexible it is. It's not as painful to make
| quick tweaks with JS as it is with a type system like
| Rust's, for example.
|
| JS, for all its quirks, made a good amount of trade-offs
| for its target platform.
|
| Type errors are almost always the easiest types of errors
| to fix. What really will get you is debugging
| interdependent systems and services, and that pesky user
| layer. But people will spend extraordinary amounts of time
| maintaining complex type systems just so their OCD can be
| satisfied about believing, that at least for a moment, if
| their program compiles...that all is right with the world
| for that brief moment just before you deploy to production.
|
| Oh were that the case. I do think types are essential for
| mission and life critical systems, but testing is even more
| essential for those cases, so everything should already be
| thoroughly covered. For consumer apps, however, is it worth
| the cost in velocity?
| marwis wrote:
| > Again, that's not what research shows. Type checking bugs
| are most definitely not the most common ones and typing
| doesn't really help with runtime bugs unless it's a
| strongly typed language.
|
| Can you point to that research?
| solumunus wrote:
| > typing doesn't really help with runtime bugs unless
| it's a strongly typed language
|
| I'm skeptical of this research. Typescript prevents
| runtime bugs for me day in day out. It also allows me to
| produce much more elegant and flexible solutions which
| would be infeasible in plain JavaScript. When people say
| there is no significant benefit compared to JavaScript it
| almost feels like I must be on a different planet or
| something. I would love to see what kind of code these
| people are working with, or how they're attempting to
| leverage the type system.
| Draiken wrote:
| This was the last one I read:
| http://danluu.com/empirical-pl/
|
| If there's more, I hope people reply here with it!
| dang wrote:
| Discussed a bit in past threads:
|
| _The evidence behind strong claims about static vs.
| dynamic languages_ -
| https://news.ycombinator.com/item?id=16287083 - Feb 2018
| (1 comment)
|
| _The empirical evidence that types affect productivity
| and correctness_ -
| https://news.ycombinator.com/item?id=8594769 - Nov 2014
| (25 comments)
| joekrill wrote:
| > The research out there found no meaningful difference between
| both styles (unless there's newer research I haven't seen?) and
| people keep taunting around how their preferred side is
| undoubtedly the right one.
|
| Does it, though? I'm not sure the research shows any strong
| evidence one way or the other. There's a decent review of
| various studies here, for example:
| https://danluu.com/empirical-pl/, that seem to indicate no real
| conclusion.
| lucasyvas wrote:
| The dynamic typing crowd is frankly just flat out _wrong_ at this
| point and someone has to say it - so, thank you Tom. This is
| especially apparent with advancements of type inference in
| compiled languages.
|
| Beyond initial prototyping (which I _doubt_ will actually ever be
| thrown away), what logical defence is there for catching obvious
| bugs in production when they could have been caught at compile
| time instead? Dynamic typing straight up hides unavoidable
| realities of programming - you have to know what thing you have
| to cover all the cases. I don 't just mean cases that "make the
| compiler happy". These cases are most often not mutually
| exclusive from the business domain - cases related to core
| business logic are missed, which produce more bugs which makes
| your software objectively worse for both the end user and
| whatever business the software is sold by.
|
| The complaints I hear are that it's too cumbersome or annoying to
| satisfy these cases - my retort is to stop complaining because
| most of us are paid to write _working_ software, not software _we
| can pass off as being complete when it 's not_.
|
| And don't suggest that tests cover this - they absolutely don't,
| and testing such things is a total waste of time. The train has
| left the station, best get aboard.
| lisper wrote:
| No one is against static typing. This thing that some people,
| myself included, oppose -- with good reason -- is _mandatory_
| static typing. The idea that anyone advocates giving up the
| ability to catch bugs at compile time if it can be done at no
| cost is a straw man.
| berkes wrote:
| Who is arguing for mandatory static typing?
|
| Even the article we're discussing points out there are cases
| for no- or dynamic typing.
| lucasyvas wrote:
| I am arguing for it, for one. There isn't a single good
| reason that it should be optional in a _production_ code
| base moving forward. If you started with a dynamically
| typed language, you should be introducing type hinting and
| enforcement at a CI /CD step as soon as yesterday.
| PaulHoule wrote:
| A counter is that nothing has replaced Python for data science.
| I mean, Julia has talked a good game but gotten very little
| traction.
| lucasyvas wrote:
| I would argue this is a false equivalency. The explanation is
| that Python is too entrenched to replace, not that it is
| somehow superior for this use case because it is dynamically
| typed.
| PaulHoule wrote:
| Well... I'd phrase it like "no statically typed language
| has proven it is superior or even applicable for this use
| case yet". You can't say Julia hasn't given it a serious
| try and hasn't gotten first-rate marketing treatment by
| being name checked in "Ju-Py-Ter" notebooks and other
| placements. Instead, Julia has serious deficiencies
|
| https://news.ycombinator.com/item?id=32806179
|
| It's certainly not proven a static language can't cover
| this use case but in other areas static languages really
| have proven their merit.
| dep_b wrote:
| I like a bit of Python or Elixir from time to time but truth to
| be said there's never a moment I am happy I didn't have types to
| worry about.
| Animats wrote:
| There's been considerable convergence on this. Most languages now
| have some degree of type inference for statements now. Even C++
| has "auto". That substantially reduced the amount of type
| boilerplate in code. Remember having to write out long iterator
| types in C++ "for" statements? We're past that.
|
| As for function declarations and structure fields, that's where
| you need type information to read the code. Once a program gets
| beyond a few hundred lines or beyond one developer, some amount
| of annotation is essential.
|
| The main objections come from Python and Javascript users, of
| course. Python retrofitted a very strange advisory typing system,
| and Javascript retrofitted TypeScript. Both are bolt-on type
| systems and are used in mixed typed/untyped environments. That is
| painful.
|
| LISP also got a type system retrofit decades ago, with "flavors"
| and the Common LISP Object System, and that was ugly, too. The
| lesson here is that retrofitting a type system creates a mess.
| mjr00 wrote:
| I actually think Python's type system is pretty good, given the
| circumstances. It's got some nice features like Optional
| forcing checks for None values before use, and structural
| subtyping with typing.Protocol. Could it be better if Python
| were designed with types from the ground up? Yeah, of course.
| But given the requirements of integrating with all existing
| Python code and not breaking any existing code I think it does
| a decent job.
|
| The bigger issue with Python and static typing is the ecosystem
| and conventions that a lot of developers use, made worse by a
| lot of these developers really being data scientists who are
| writing Python. *args/**kwargs are heavily abused by people too
| lazy to write proper method signatures. It's extremely common
| in Python to have methods pass around DataFrames or
| dictionaries as a grab-bag of stuff. Bonus points when methods
| add and remove columns/fields so you don't know what's in the
| data bag until you run the code (or read every line).
|
| You can do this in almost any language, of course. Nothing
| stops you from writing a C# program with every type being
| `dynamic` or have all your Go methods accept `interface{}`. But
| Python, for a long time, actively encouraged this approach, and
| sadly there's still many beginner tutorials today that present
| things like "just write a method that takes *kwargs and you
| don't have to change the function signature!" as an advanced
| language feature for smart people instead of an awful footgun.*
| germandiago wrote:
| Python and Typescript "type systems" were designed for gradual,
| non green-field typing. It is essential to incremental
| migration and totally understandable that it works this way.
| spankalee wrote:
| TypeScript's type system is flat out amazing though. I wish
| more type systems were as expressive.
| Byamarro wrote:
| TS' type system is insane in what it's capable of expressing.
| I've personally wrote a snake game using types alone (you see
| a board, snake and snacks inside your editor type popups).
|
| Despite that, TS is still quite cumbersome to use due to its
| initial mission statements. I.e. `Object.keys(myObject)`
| doesn't return `keyof (typeof myObject)`, so if you'd do
| something like this: `Object.keys(myObject).forEach(key =>
| myObject[key])` it'll throw an error that key is not
| assignable to `myObject`. The reasons lie in design choices
| made in order to be able to gradually migrate an untyped JS
| codebase into a TS one. There's tons of issues like this,
| some of them are just completely absurd and make developers
| that try to achieve simple things throw their laptop out of
| the window :D
| spankalee wrote:
| This is an old, old issue, and it's not due to migration
| but due to inheritance.
|
| `<T>keys(o: T) => keyof T` is actually quite incorrect,
| because you can't guarentee that keys() doesn't return a
| value not in `keyof T`, a key could be from a subclass of
| T.
|
| I think TypeScript is doing the right thing here in not
| claiming something that's very easily violated.
| zabzonk wrote:
| i agree about strongly typed languages, but rather than:
|
| let person1 = new_person();
|
| i prefer the c++ way (which also supports type inference):
|
| Person person1;
| Veuxdo wrote:
| Static type checking won the battle, but lost the war to
| microservices, micro front-ends, micro-repos, and so on.
| feoren wrote:
| We want to identify and fix problems as early as possible;
| ideally, before we even write them. Problems cost exponentially
| more to fix the later you catch them, and the damage they can
| cause only grows with time. Static typing lets you identify
| problems earlier than dynamic typing, full stop. In fact I'd
| rather have strong static typing and 0% test coverage than
| dynamic typing and 100% test coverage -- in the latter case, I'm
| catching problems much later, and I have the maintenance burden
| of all those tests, 70% of which are only there to catch what
| static typing would have already found.
|
| The best mix for me is to lean heavily on the type system and
| only lightly on tests, trying to write code that is simple and
| "obviously correct". Obviously-correct code has already had its
| problems ironed out in the first 6 or so bullets below, and there
| is very little room for further bugs to hide. Of course even
| "obviously correct code" can actually have bugs or be subtly
| incorrect -- a better definition is that any surprises in such
| code would _also_ be surprises to the tests. The tests are
| nothing more than mirror images of the code, and therefore are
| not helpful or necessary. Static typing helps me think about the
| problem clearly, and helps me write "obviously correct" code.
|
| Here's my working list, in order of preference of when I'd like
| to find the problem. Every time you drop down this list, the cost
| to fix the problem gets multiplied by some small factor ~1.5 to
| 3.
|
| - Initial ideation ["Facebook for dogs? That idea sucks."]
|
| - Requirements analysis ["That's not actually how we calculate
| that metric."]
|
| - Conceptual system design ["Wait, these parts don't fit together
| like that."]
|
| - Low-level design ["Crap, a loop won't work here, I need a
| different flow."]
|
| - Brain-to-fingers typing ["Whoops I almost typed 'elesif'"]
|
| - Immediately post-typing [Red squiggly line under 'elesif']
|
| - Re-reading ["Wait that should be i-1, not i"]
|
| - Compile time ["SYNTAX ERROR: Unknown identifier 'elesif'"]
|
| - Unit test time ["Assertion failed: expected 7, got 8"]
|
| - Code review time ["You didn't handle the case where N is
| negative"]
|
| - Merge / integration test time ["Oh crap, David's commit broke
| my commit! How the hell do I merge this?"]
|
| - Internal manual testing time ["You need to tighten up the
| graphics on level 3"]
|
| - Production ["The users say the application keeps crashing when
| they run this report! Fix it!"]
|
| - Years later/never ["It turns out that the analysis code we've
| used for the last 10 years had a major bug in it the whole time
| and we've been giving wrong numbers to a regulatory agency that
| has the power to shut down our company."]
| boxed wrote:
| > Problems cost exponentially more to fix the later you catch
| them, and the damage they can cause only grows with time.
|
| Citation needed.
|
| This is ENORMOUSLY context dependent. Enough to invalidate the
| entire point.
|
| My day job is writing code that runs on a server I control.
| Mistakes there are super cheap to fix. I get a nice crash in
| sentry with stack and variables for all frames, I fix it,
| deploy. Done.
|
| If I was shipping code to Mars, well that's the opposite
| situation.
|
| CONTEXT MATTERS
| feoren wrote:
| >> Problems cost exponentially more to fix the later you
| catch them, and the damage they can cause only grows with
| time.
|
| > Citation needed.
|
| Really? Isn't this one of the most clear and repeatedly
| demonstrated facts in all of software engineering? We don't
| have a whole lot of clear-cut demonstrable facts in this
| industry, but this is absolutely one of them.
|
| How about this 2002 NIST report, Table 1-5 on page 1-13 is
| "Relative Costs to Repair Defects when Found at Different
| Stages of the Life-Cycle" and shows 1X at "Requirements", 90X
| at "System Testing", 440X at "acceptance testing", and up to
| 880X at "operation and maintenance".
|
| (Warning: 300-page PDF)
|
| https://www.nist.gov/system/files/documents/director/plannin.
| ..
|
| You can find thousands of people saying the same thing from
| their personal experience with a quick Google. On the list of
| uncontroversial statements about software engineering, this
| is right at the top. Is our discipline so immature that we
| can't even agree on this extremely basic fact?
|
| Another (okay, they don't say "exponential" here, or try to
| quantify it at all):
|
| > The cost of finding and fixing bugs or defects is the
| largest single expense element in the software lifecycle. ...
| The earlier in the development lifecycle defects are found,
| the more economical the overall delivery will be.
|
| The Cost of Poor Software Quality in the US: A 2020 Report,
| Consortium for Information & Software Quality
|
| https://www.it-cisq.org/cisq-files/pdf/CPSQ-2020-report.pdf
|
| > My day job is writing code that runs on a server I control.
| Mistakes there are super cheap to fix.
|
| That's good to hear, but mistakes caught before they get to
| your server are even cheaper still. Perhaps your exponential
| factors are smaller than NASA's, but it still clearly costs
| you much more to fix a problem that made it to your
| production server (and possibly impacted your users) than to
| fix it immediately after typing it because your IDE showed
| you a red squiggly line.
| boxed wrote:
| > Really? Isn't this one of the most clear and repeatedly
| demonstrated facts in all of software engineering?
|
| It's a repeated saying.
|
| > You can find thousands of people saying the same thing
| from their personal experience with a quick Google.
|
| I know.
|
| > That's good to hear, but mistakes caught before they get
| to your server are even cheaper still
|
| That's a nonsense statement. If they are caught AT NO COST
| they are of course cheaper yea. But that's the thing. It's
| all tradeoffs. Everything is about tradeoffs. What is the
| marginal cost of finding bugs?
|
| > than to fix it immediately after typing it because your
| IDE showed you a red squiggly line.
|
| Yea, that's nice. In that case the marginal cost is
| approaching zero. But how many percentage of all bugs is
| that? And what is the cost?
|
| How many bugs will my IDE find if I switch from Python to
| Haskell or Rust? And how will that impact my development
| speed?
|
| I write my frontend in Elm because that's code I ship to
| users (via the browser) and THERE the costs are enormously
| worse, often because the problems can be seen by customers
| and not internal users (again: CONTEXT). I'm willing to
| tolerate a big productivity cut for being sure the code is
| correct there. But on my server? Nope. I am not willing to
| leave an easy order of magnitude of development time on the
| table for that type of safety.
|
| And why stop at static typing? Why don't you run ALL your
| code through Property Based Testing AND Mutation Testing
| 100% before shipping? What's the marginal cost of catching
| a bug then? Why not run ALL your code through a theory
| prover like Coq?
|
| Bugs are NOT always "cheaper" when found early. It's about
| the COST of finding the bug early. Of course it is! If the
| cost is a trillion dollars in programmer time to find a bug
| that takes 1 second to fix in production at a cost of a few
| dollars of programmer time, by definition it was NOT worth
| it.
|
| It's ALWAYS a tradeoff. Of course it is. Everything is.
|
| It's maddening to me that people refuse to see this when
| it's so blatantly obvious.
| feoren wrote:
| There's a reason I used the word "problem" and not "bug"
| in my original post. In fact every time I found myself
| writing "bug", I deleted it and wrote "problem" instead.
| You're thinking very specifically about "bugs": clear
| spots a codebase that are clearly causing some clear
| error. That's actually a small percentage of the scope of
| "problems" that I'm talking about. Problems can be: your
| idea is bad, your architecture doesn't fit together, your
| performance is bad, your calculations are wrong, etc.
| Static typing, when done well, can help prevent many more
| of these issues than that narrow definition of "bug".
| Static typing helps you think clearly about your code.
|
| > the marginal cost [of fixing a red squiggly] is
| approaching zero. But how many percentage of all bugs is
| that? And what is the cost?
|
| The marginal cost of fixing a red squiggly underline is
| indeed basically zero for typos, and typos are a class of
| bugs I'd like my static type system to help me catch; and
| it does, and dynamic type systems generally don't. So the
| percentage of typos that become bugs is basically zero,
| but that's partly _because of static typing_! When you
| say "the percentage of all bugs", your definition of
| "bug" is a-priori excluding things that were caught
| before they became bugs!
|
| But you can also get a red squiggly underline because you
| thought some variable was in scope when it's actually not
| -- that bug _could have been caught earlier_. The cost of
| fixing that bug is _not_ near zero: the structure of your
| program is different between your brain and your code.
| The easiest bug to fix is the one you never write in the
| first place.
|
| Or you get a red squiggly because you thought you could
| pass an object of type X into a method you're relying on,
| but you actually can't. Dynamic typing _will not help
| you_ with this, and the cost of fixing that bug is _not
| zero_ : again, your assumptions about how your program is
| fitting together are incorrect. I'd much rather realize
| that I can't use a method in exactly the way I thought
| right at the moment of typing it than later during test
| time. The latter requires writing and maintaining a test
| in order to catch a problem _late_ that I could have
| caught _early_ with _no test_.
|
| > And why stop at static typing? Why don't you run ALL
| your code through Property Based Testing AND Mutation
| Testing 100% before shipping?
|
| I directly addressed the subject of testing in my
| original post. Static typing allows me to write many
| fewer tests than dynamic typing.
|
| > If the cost is a trillion dollars in programmer time to
| find a bug that takes 1 second to fix in production at a
| cost of a few dollars of programmer time, by definition
| it was NOT worth it.
|
| I just don't understand this hypothetical. Why would it
| ever take a trillion dollars to prevent a bug that takes
| 1 second to fix in production? This just doesn't jive
| with any developer experience I've ever heard about, any
| example I've ever read about, or anything I can even
| imagine.
|
| You seem to be operating under the assumption that
| introducing static typing makes you slower at
| programming, but we're claiming it's worth it. No, that's
| not my claim. My claim is that above some level of
| program complexity, static typing makes you _strictly
| faster at programming_ , full stop. That level of program
| complexity may not be your internal server or whatever,
| but it definitely is most production-grade software out
| there.
|
| > It's ALWAYS a tradeoff. Of course it is. Everything is.
| It's maddening to me that people refuse to see this when
| it's so blatantly obvious.
|
| This is generally true in engineering, but not always. It
| is actually possible to simply advance the discipline.
| When you're building a suspension bridge, there's a
| tradeoff between Stainless Steel and High-Carbon Steel,
| but there's not a tradeoff between Steel and Popsicle
| Sticks. Unless, of course, you're building a toy or a
| proof of concept. Dynamic typing is fine for toys and
| proofs of concepts; nobody is disputing that.
| Professional engineers don't spend most of their time
| discussing the best way to build toys.
| boxed wrote:
| > Problems can be: your idea is bad, your architecture
| doesn't fit together, your performance is bad, your
| calculations are wrong, etc. Static typing, when done
| well, can help prevent many more of these issues than
| that narrow definition of "bug".
|
| I don't see how static typing helps with "solving the
| wrong problem" kind of issues at all. That's what asking
| deep questions about the business is for. Maaaaybe DDD
| can do something here, but that's hardly "static typing".
|
| > I directly addressed the subject of testing in my
| original post. Static typing allows me to write many
| fewer tests than dynamic typing.
|
| I noticed here that you didn't make any difference
| between testing, PBT, MT and proof systems. That's pretty
| bad. I won't conflate Haskell-style good type systems
| with C-style horrible type systems, so you shouldn't do
| the same with testing.
| feoren wrote:
| > I don't see how static typing helps with "solving the
| wrong problem" kind of issues at all.
|
| One example is F#'s unit of measure system, which can
| statically verify dimensional agreement of arithmetic.
| Another example would be differentiating between "Safe
| Strings" and "Unsafe Strings" (say, untrusted user input)
| and statically enforcing which are allowed in which
| method. They won't tell you that "Facebook for Dogs" is a
| bad idea, but they may reveal subject-matter errors in
| the actual requirements themselves. Most test suites
| wouldn't even catch these errors, because test assertions
| are generally based on requirements. You could write your
| own unit-verifier that you run in tests, but then you're
| just reinventing static typing. In fact it's a common
| criticism of test suites in dynamically typed languages
| that they end up poorly reinventing checkers for the
| guarantees already provided by a decent static type
| checker.
|
| > I noticed here that you didn't make any difference
| between testing, PBT, MT and proof systems
|
| I also didn't differentiate between the Late Middle Ages
| and the Early Renaissance, because it was off topic. But
| if you insist:
|
| "Property-Based Testing" is a testing pattern, not a
| different kind of test. Write tests and assertions as
| appropriate for the thing you're testing. It seems to me
| that you should have enough understanding of the likely
| failure scenarios and edge cases of your code that you
| don't need to be randomly generating inputs, but I can
| see how it'd be useful. I test all sorts of invariants in
| my tests. This just doesn't seem like a novel thing to
| me.
|
| "Mutation Testing" is basically testing your testing
| methodology. Okay. You could also test your bus factor by
| randomly shutting out one developer for a day each month
| and seeing how you get on. Maybe good ideas for some
| companies? If you find yourself trying to develop a
| completely airtight testing process that will catch 100%
| of bugs, it's probably because too many bugs are passing
| your tests. Before you kill yourselves trying to develop
| an airtight, mathematically-guaranteed strong test
| system, may I suggest strong static type systems instead?
| Just let the compiler do it.
|
| "Proof systems" _are_ strong static type systems.
| t43562 wrote:
| I also don't want to get into a debate about something where
| there's no chance of changing an opinion. An absolute position is
| like a religion - it's the desire for everything to be simple,
| for the removal of doubt and the need to think about each
| situation on its merits.
|
| I remember taking a badly written Python project which was
| difficult to work on because it took hours to run and could fail
| at the very end due to a syntax error or other trivial kind of
| mistake. I needed some way to make it less difficult to change so
| I could change it to something good. I tried applying type hints
| because I thought this had minor impact for potentially some
| gain. In this case it didn't and what helped was to take every
| tiny bit that was unit-testable and make a test and then to mock
| the part of the process that took all the time (it was an android
| build system so I mocked the android build). Every bit of
| refactoring-for-testability made it easier to do the next bit.
|
| So to me I feel that writing tests has more value than any other
| activity - I'm ready to use types when it makes my IDE work
| better and when I think it stops me making a mistake I've made
| before but for my money tests deliver more and I will rather work
| on them than trying to build an elaborate type system that models
| the problem well enough to prevent one from doing invalid things
| under any circumstances. For me, the types/classes I create are
| there to make my program understandable and manageable as it gets
| bigger.
|
| I find it useful to be able to choose where to put my effort.
| When I worked on Java long ago I found the type system of the JDK
| libraries horrendously overdesigned and hard to use - flexibility
| is sometimes bad if you don't gain from it but are forced to pay
| the price anyhow.
| kagakuninja wrote:
| Python is an example of adding types after the fact. I don't
| know the specifics of your situation, but gradually typed
| languages do not offer the same guarantees as languages that
| have static type checking from the beginning.
|
| Replacing types with tests adds giant amounts of boiler-plate
| code, for little benefit.
| t43562 wrote:
| My experience is that tests model the expected behaviour and
| that type systems cannot. Therefore I get lots of value out
| of tests where types are an impediment.
|
| Static typing from the beginning just sets me into a big
| design up front problem where I try to anticipate the
| flexibility that I will need and I start building lots of
| boilerplate abstractions that end up never being used or
| restricting me later.
|
| I find it useful to write imperfect code with only the
| constraint that it is testable and then revise the structure
| and any types I need as it becomes evident that they are
| valuable in the context.
| Zambyte wrote:
| I agree with the title, but not with the blog post. Strong typing
| is great. There is little reason not to use strongly typed
| systems.
|
| The post adds "static" typing in too, modifying the argument.
| Dynamically typed languages allow you to easily have a very
| intimate understanding of your program; because you can write the
| program and modify it while it's running using a REPL. The post
| seems to conflate dynamically typed with untyped, which is very
| much not the same thing. The two are actually incompatible ideas.
|
| OP: I highly recommend you look into SICP if you want a concrete
| counter argument to static typing for large systems. A main focus
| of the course is controlling complexity through abstraction as
| systems grow to be large, and the course was taught using Scheme,
| which is a dynamically typed language.
| vonwoodson wrote:
| First off, I appreciate the edit. python is strong _dynamic_
| typing, for example.
|
| Second, it's a shame that the author doesn't really speak to
| Haskell at all. Knowing that a variable is a `u16` is rarely
| useful alone, relying on the meta of a variable name, for
| example, to prevent me from adding `user_age` and
| `number_of_legs`; they both are unsigned 16-bit `int`s, so the
| compiler is cool with it. A better type system allows types to
| hold semantic information beyond the bit-width or archaic and
| usually unhelpful information for the computer and not the
| developer. Relics of a past where 8k or RAM was all you could use
| for your program.
|
| Ironically, the advanced Haskell type system looks more like
| dynamic typing specifically because the type inference is so
| good. You can rely on the compiler (or interpreter) to tell you
| what the type should be, often times allowing for much more
| flexible types than you'd think possible.
|
| Also, being able to derive classes like Show and Read is amazing.
|
| So, +1 for loving types!
| tubthumper8 wrote:
| I'm sure the author is aware of these - many of the code
| examples are in Rust which has newtypes and automatic deriving
| of traits (ex. Display which is the equivalent of Haskell Show)
| syndicatedjelly wrote:
| Does mypy for Python offer a complete solution to introducing
| static type checking to Python? What is mypy missing that a
| language with strong static typing has?
| [deleted]
| terminatornet wrote:
| It's a shame so many people have had bad experiences with static
| typing due to Typescript. In languages like Rust and Elm, static
| typing truly feels like a super power when I'm coding,
| particularly when modeling my applications possible states.
|
| This talk does a great job at articulating how to use types to
| disallow invalid/illegal states.
|
| https://www.youtube.com/watch?v=IcgmSRJHu_8
| bluetomcat wrote:
| Dynamic typing is polymorphism at the language level. In essence,
| you expect most operators to behave sensibly with different
| types. An expression such as "a + b" resembles a polymorphic
| function such as "add(a, b)". You would expect it to work fine
| most of the time, regardless of the types. And the types in a
| dynamically-typed language usually aren't so many - you possibly
| have booleans, numbers, strings, lists, maps, sets and objects.
| Chabsff wrote:
| The moniker you are looking for is "duck-typing". Polymorphism
| is tightly tied to the notion of explicit interfaces.
| jwilliamson wrote:
| He's describing row polymorphism. Only some forms of
| polymorphism require explicit interfaces.
| incomingpain wrote:
| I learnt to code in C. I know strong static typing.
|
| I now program exclusively in python. I am never going back.
|
| I have tried and do have some of the
|
| def hello(world: str) -> str:
|
| But to date I have not found a single example where this was
| useful at all. In fact, I found some odd cases where it's
| harmful.
|
| No typing for me thanks.
| EVa5I7bHFq9mnYK wrote:
| Hmm, just a few years ago, before typescript, the prevailing
| wisdom was that types are dead, this is a brave new world out
| there, just need to create more unit tests.
| strongly-typed wrote:
| TIL I am a hill
| revskill wrote:
| THere's a trick i often do on my Typescript projects.
|
| To know which other files is using current file, i just add an
| additional property, then boom, the IDE go red on those files !
|
| Without types, the best you can do is, search, search and search
| !
| 1-more wrote:
| This is a whole vibe when working with an ML language. I
| usually start at the bottom of the call stack and add the
| property I need to the signature of that function, then I can
| just follow "hey, you're calling it wrong--where is argument
| xyz?" errors up to the top of the stack. Classic bop mode.
| insanitybit wrote:
| At this point it's beyond a hill I'm willing do die on. I'm not
| really interested in discussing it. If you don't get it I
| probably don't want to talk to you about it, I might even think
| less of you as a software developer. The amount of pre-existing
| respect for someone I'd need to have before I engage in a good-
| faith discussion on "are types good" is pretty high.
|
| edit: To clarify, I am on the "types good" side of things
| edem wrote:
| Same here. Whenever someone starts babbling about why
| __language x__ is hard because of types or whatever, I just
| disengage. I don't care what anyone thinks about types. I use
| them, and I will keep using them no matter what.
| yowlingcat wrote:
| > The amount of pre-existing respect for someone I'd need to
| have before I engage in a good-faith discussion on "are types
| good" is pretty high.
|
| I think that says more about the strength of your zeal than of
| your argument.
| pharmakom wrote:
| Also on the "types good" side of the fence. HOWEVER, I also
| believe that mainstream typed languages cannot represent some
| situations very well. Often the only attempts to do so are in
| some weird Haskell extension and it feels rather... inelegant.
| Bottom line: types are better; but our current type-systems are
| not the final word on types.
| wiseowise wrote:
| The only absolute truth there is. Static typing is
| nonnegotiable.
| dartos wrote:
| There's strong typing and weak typing.
|
| And then, kind of orthogonal to that, there's also static
| typing and dynamic typing.
|
| I think strong, dynamic typing is just as good as strong
| static typing (weak typing is objectively bad)
|
| As long as the types of your variables don't change from
| under you, that's good, but I'm also okay with the compiler /
| runtime figuring out what those types are for me.
| chongli wrote:
| With "dynamic typing" there is no compiler to figure out
| the types for you. There is only the runtime to print a
| stack trace (if you're lucky) and bail out. The whole point
| of types is to be able to check things without running the
| program, because exercising every possible code path
| becomes increasingly untenable at scale.
|
| A side (but many would also say critical) benefit of types
| is that they act as a form of documentation that can never
| go stale (because they are enforced by the compiler).
| "Dynamic typing" does not offer this benefit whatsoever.
| k__ wrote:
| As far as I know, JS is weakly typed and Python is
| strongly typed.
|
| JS will convert types under your butt if you're not
| careful, Python won't.
|
| Sure, static typing (when done well) is superior to that,
| but the title talks about strong typing.
| dartos wrote:
| Many dynamically typed languages have static analyzers,
| but retain the flexibility of not needing to prescribe
| types up front (it's impossible to know exactly what data
| structure you need at the start of a project)
|
| That's the crux of why I'm not all in on static typing
| all the time. (Especially for networked programs that
| expect a wide range of different kinds of input)
|
| Having to prescribe the types I need before I actually
| need them goes against how I tend to build.
| sfn42 wrote:
| Sounds like you'd like C#. It does type inference with
| `var` and similar things, so you don't always have to
| specify types explicitly, but everything does have a type
| at compile time.
| Smaug123 wrote:
| (C#'s type inference is _so_ much worse than F# 's. I
| find it deeply painful to go back.)
| loup-vaillant wrote:
| > _Many dynamically typed languages have static
| analyzers, but retain the flexibility of not needing to
| prescribe types up front_
|
| Almost all static type systems have escape hatches that
| let you go dynamic when you really really need it. Also,
| I bet that most of your use cases for dynamic typing
| could be solved with a simple tagged union. Most people
| bemoaning the lack of flexibility of static typing just
| don't know about how tagged unions can easily emulate
| dynamic typing when we need it, such that we rarely even
| need to reach for the actual escape hatches.
|
| > _(it's impossible to know exactly what data structure
| you need at the start of a project)_
|
| Thankfully data structures are even _easier_ to change
| with static typing: change it, gets a ton of type errors,
| fix them, done. With dynamic typing you run the risk of
| missing a call site.
|
| > _Having to prescribe the types I need before I actually
| need them goes against how I tend to build._
|
| There's type inference for that. I personally take
| advantage of it any chance I get.
| pfdietz wrote:
| Dynamic typing doesn't exclude the compiler from being
| able to detect some things that would cause errors at run
| time. It just means that these turn into compile time
| warnings, not compile errors.
|
| In Common Lisp, it's common practice to not accept code
| unless all such warnings are gone.
| chongli wrote:
| That is static typing. You can add static types to a
| dynamic language, but then you introduce a compilation
| step. This is not an argument in favour of dynamic
| typing. If your language requires a compilation step
| anyway, then what you have is a static language with only
| one type: the 'any' type.
|
| Every argument I've seen in favour of dynamic typing is
| some variation of "I like it this way." They're not
| technical arguments because dynamic typing is a strict
| subset of a statically typed language, equivalent to
| passing a flag to turn the type checker off.
|
| Sure, not every compiler offers such a flag, but that is
| an argument against one particular static language (or
| group of languages), not an argument against static types
| itself.
| marcosdumay wrote:
| > There is only the runtime to print a stack trace
|
| Types are not exclusively for verification, and even if
| you decide it is, you can do a lot more with a type error
| than exiting the program.
|
| That stance most people keep repeating is actually
| ridiculous. The most common usage of static type systems
| is to verify badly-written ad-hock dynamic ones that
| handle user errors.
| IKantRead wrote:
| Dynamic vs static typing is a similar level of design
| decision as interpreted versus compiled. It's ridiculous to
| try to claim one is universally better than the other as they
| both have styles of programming and domains they are better
| suited for.
|
| I would never want a statically typed, compiled awk for
| example.
|
| I generally think large, production, multi-developer software
| should be written in a statically typed, compiled language.
|
| Strong vs Weak typing is a closer to a debate about having a
| name spacing system or not. There is really no great reason
| to have weak typing or not use a name spacing system.
| wiseowise wrote:
| It's not ridiculous at all.
|
| Mainstream dynamically typed languages are moving in
| statically typed direction. Python (Mypy, Pyright and
| others), Ruby (Sorbent, Rbs), JavaScript (Typescript,
| Flow). How many statically typed languages optionally
| removed types?
| IKantRead wrote:
| It's a bit sad to me that people can only imagine writing
| code for large production systems. Static types are
| hugely beneficial in this area which is why we see this
| trend.
|
| Personally I think Python moving in the direction of
| static typing is a mistake, dynamic typing _is_ very
| useful for domains where python is strongest: modeling,
| statistics, scientific computing etc. It 's also part of
| the basic design of Python to be a dynamic language.
| Likewise Ruby, with it's heavy use of metaprogramming,
| also benefits tremendously from a lack of types.
|
| But let me be clear: I do think statically typed
| languages are a very good idea for large production
| systems, I just personally do a lot of programming that's
| not for these systems.
|
| > How many statically typed languages optionally removed
| types?
|
| I wouldn't say "removed" types, but I've been in software
| along enough to remember when dynamic typing was the big
| hot thing and crusty old Java devs complained that we
| couldn't possibly live without static type annotations. I
| distinctly remember when C# introduced `var` (which is of
| course really type _inference_ , not dynamic typing) to
| appeal to devs that were growing weary of types.
|
| There's a great example in SICP of implementing a full
| object system in just a few lines of code that would not
| be possible to implement as elegantly in a statically
| typed language. Do I want that for a production system?
| No. But there is, or at least used to be, a world of
| computation being done for reasons other that quickly
| getting PRs pushed out to prod.
| wiseowise wrote:
| Ok, maybe my previous message was too radical. Of course
| there's a space for dynamic types (I use Clojure in free
| time), but there's no reason for static types to obscure
| your program. When I talk about static typing I mean
| Ocaml, Haskell, Scala, F# where you program is statically
| typed but you'll rarely see any types.
| fargle wrote:
| _and yet..._ here you are discussing it. ;)
|
| discussions are a two-way street. if you aren't getting it,
| then how do you expect someone else to "get" your position?
| "The whole problem with the world is that fools and fanatics
| are always so certain of themselves, and wiser people so full
| of doubts"
|
| -- Bertrand Russell
|
| [edit: To clarify, i am on the "i like strong static typing
| most of the time but also understand their pros/cons wrt.
| dynamic languages" side of things]
| yetanotherasian wrote:
| How often do you write bash scripts or do you always write all
| automation in some other language? Just curious how much your
| conviction influences your behavior
| insanitybit wrote:
| I write code without static types all the time. Daily
| probably. I am "pro types" in a hand wavy way. My conviction
| is to no longer engaging in the debate.
| scbrg wrote:
| I'm glad to see that you've replaced debating type systems
| with debating debating type systems. I'm sure it's a great
| productivity improvement ;-P
| insanitybit wrote:
| It's not like I've barred myself from engaging in any
| discussion where the word "type" shows up
| bigstrat2003 wrote:
| Speaking for myself, I never write bash scripts if I can help
| it (though sometimes I can't help it). That isn't so much
| because of typing, though... it's because bash is a fucking
| horrible language that should have died 30 years ago. The
| fact that there's no such thing as types in bash is just one
| of many reasons why it sucks to use.
| thefaux wrote:
| > If you don't get it I probably don't want to talk to you
| about it, I might even think less of you as a software
| developer.
|
| The feeling is mutual.
| omnicognate wrote:
| > The amount of pre-existing respect for someone I'd need to
| have before I engage in a good-faith discussion on "are types
| good" is pretty high.
|
| > edit: To clarify, I am on the "types good" side of things
|
| I agree. Python 1 would have been worthless if it didn't have
| types.
| codegeek wrote:
| I don't necessarily die on that hill but I definitely want to
| fight on that hill.
| lasermike026 wrote:
| Understand that there is no hope. You will die on that hill.
| Get over it.
| tasn wrote:
| Author here. I ended the post with:
|
| > I can see both side of the arguments on many topics, such as
| vim vs. emacs, tabs vs. spaces, and even much more
| controversial ones. Though in this case, the costs are so low
| compared to the benefits that I just don't understand why
| anyone would ever choose not to use types.
|
| > I'd love to know what I'm missing, but until then: Strong
| typing is a hill I'm willing to die on.
|
| I genuinely want to know what I'm missing. I also outlined in
| the post all of the arguments I usually see in favor of not
| having types and why I disagree with them.
|
| I'm happy, willing, and excited to hear what I'm missing.
| 1-more wrote:
| What does "strong" mean as regards typing. I've heard a few
| different definitions so I'm curious what yours is in the
| context of this article.
| bigstrat2003 wrote:
| As far as I'm aware, the generally accepted definition of
| strong typing is: some object in memory has a type, and the
| compiler (or interpreter) will not let you treat it as
| another type without some kind of explicit instruction to
| do so. This is in contrast to weak typing, where the
| compiler/interpreter will happily try to treat a Bar object
| as a Foo object if you do some Foo operation on it.
| gpderetta wrote:
| That's the definition of type-safety (or memory safety
| that is pretty much equivalent). "strong typing" has no
| generally accepted definition.
| bigstrat2003 wrote:
| Memory safety is definitely not equivalent. Memory safety
| is more like not going past the end of an array, not
| doing use after free, etc. I agree that what I said is
| pretty much also the definition of type safety. But in my
| experience it is _also_ the generally accepted definition
| of strong typing.
| 1-more wrote:
| That seems to be a subset of static typing. Is there an
| example of this that does not involve non-static typing?
| user3939382 wrote:
| There's a specific scenario where I have more sympathy for
| weak typing, which is: I'm writing a small, focused utility
| by myself whose scope can never expand and whose code will
| never be collaborated on. I do have these, little shell
| scripts. I write them, they work, I move on and use it for 10
| years. No types in there, fine whatever.
|
| As soon as there's any complexity at all or another person
| involved that exception stops.
| SAI_Peregrinus wrote:
| I want a shell scripting language that allows a max line
| length of (for example) 128 characters and a max script
| length of (for example) 128 lines, with no `source`
| equivalent. If the script expands to not be a "small,
| focused" single-file script it should just fail to run at
| all. Just enough for small utilities, but unusable for
| giant monstrosities.
| KMag wrote:
| ... and unable to call external programs or communicate
| with external programs via pipes / sockets / etc.?
|
| Otherwise, if you're unable to source another script, you
| could just have another script return a normal result in
| addition to a JSON blob of the environment variable
| changes the caller should make, which is probably worse
| than just allowing sourcing.
|
| Pipes allow arbitrarily complex networks of communicating
| sequential processes. In some cases, networks of tiny
| CSPs are cleaner, but without discipline, they can
| rapidly become worse than huge monoliths.
| racked wrote:
| Indeed this. There are benefits. Less code, faster to
| write.
| KMag wrote:
| Note that weak typing and dynamic typing are orthogonal. I
| believe you're expressing sympathy for strong dynamic
| typing: types are checked an enforced dynamically by the
| runtime (such as Python raising an exception if you try to
| add a string and an int), but there's no static type
| analysis done at compile / load time. Python, JS, Ruby,
| etc. are strong dynamically typed languages.
|
| Also, type weakness is more a property of the runtime than
| the language, but for those languages with specifications,
| the language specification usually also specifies a large
| amount of behavior for a compliant runtime.
|
| The C runtime, will gladly (with UB nasal demon caveats)
| allow you to treat an int as a pointer. There are static
| type checks, but no hard limits on the type-confused
| nonsense it will attempt to execute. C is statically typed,
| but weakly typed.
|
| Java, C#, etc. are strong statically typed. There are
| static checks at compile time, and the runtimes do their
| best (modulo escape hatches) to use dynamic runtime type
| checks to plug the gaps in the static type systems. (For
| any sufficiently complex sound/consistent type system in a
| Turing-complete language, as per Godel's incompleteness
| theorem and the halting problem, there will be some
| programs that cannot statically type-check but still will
| never encounter a type error, regardless of input. So, in
| practice, there will always be escape hatches in the type
| system to allow programs that are correct but not provable.
| Hopefully most of these escape hatches are backed by
| dynamic runtime checks.)
|
| Of course, these categories are a partially-ordered
| continuum, not clear binary distinctions. For some pairs of
| languages, you can say one's statically enforced properties
| are a superset of the other or that one runtime enforces a
| strict superset of the other's dynamic checks. However,
| it's often a case that you can't say one language strictly
| offers stronger static type guarantees or one runtime
| strictly enforces stronger dynamic type restrictions.
| user3939382 wrote:
| I'm aware of the difference, I was contemplating bash in
| my comment. Some people construe it as strongly typed
| though it's a little ambiguous, here's another discussion
| about it https://news.ycombinator.com/item?id=12704050
| AnimalMuppet wrote:
| You are the other person. Come back in six months needing
| to make a change, and it's almost like you're new to the
| code.
|
| Now, in general, I agree with you. If it's a one-off (or if
| it's really never going to need maintenance), and if it's
| small enough that you don't need types while writing it,
| then sure, do whatever is easiest at the time. But "never
| going to need maintenance" often turns out to be a lie, and
| when that time comes, you may be happy for some types as
| signposts to give a hint of what you were thinking all
| those months or years ago.
| BobbyJo wrote:
| This is the trojan horse dynamic types use to get into
| your castle :P
| sumtechguy wrote:
| Weak typing has its uses in one use case. Transition between
| systems. Even then you usually want to know what the type is
| (unless you really do not care about validation errors).
|
| The reality is I never get to choose. I prefer strong typing.
| But the projects I am on that ship sailed long ago 2
| developers back who used this project as a resume builder.
| a_c wrote:
| I think you and parent are in agreement
| packetlost wrote:
| I'm also a pretty die-hard type-system user, but I've been
| programming a lot of Lisp and FORTH lately. FORTH is just bad
| at safety period. Lisp, on the other hand, I can see why
| there really isn't a need for types. The macro system means
| you can create arbitrary "compile-time" safety checks which
| is, IMO, more powerful than just a type system. That being
| said, I would still love a strongly, statically typed Lisp,
| or at least one with a strong macro type system (before y'all
| mention it, I'm not a fan of typed Racket).
| gpderetta wrote:
| wait, are you saying that any sufficiently complicated lisp
| program contains an ad hoc, informally-specified, bug-
| ridden, slow implementation of a static type system?
| qazwse_ wrote:
| I haven't used it, but I know that Coalton adds static
| typing to Common Lisp, might be something you're interested
| in.
|
| https://github.com/coalton-lang/coalton
| packetlost wrote:
| I'm more into Scheme than CL, but am aware of Coalton. My
| current lisp is Gerbil: https://cons.io which already has
| a type annotation system and will be enhancing it for the
| next major release (v19).
| Zambyte wrote:
| > Lisp, on the other hand, I can see why there really isn't
| a need for types.
|
| What Lisp are you using that doesn't have types?
| packetlost wrote:
| Well, every programming language must necessarily have
| types to some degree, but they aren't necessarily static
| or strong type systems. Most Lisps do not have a static
| type system and even fewer have a "strong" type system.
| Zambyte wrote:
| > Well, every programming language must necessarily have
| types to some degree
|
| The vast majority yes, that's why I was a bit confused :D
|
| There some languages that have no types. The only thing I
| can think of though is a POSIX shell minus arrays. (Edit:
| Assembly and Forth are two better examples)
|
| > Most Lisps do not have a static type system
|
| True
|
| > and even fewer have a "strong" type system.
|
| Common Lisp, Emacs Lisp, Scheme, Hylang, Clojure, and
| Racket all feature strong typing. I'm curious where you
| have found this trove of weakly typed Lisp dialects
| packetlost wrote:
| Lisps are not _statically_ typed typically and
| "strongly" typed is poorly defined. I would not consider
| most Lisp's type systems to be strong or particularly
| expressive, but they don't need to be because it would
| hurt the main benefit to the language: meta-programming.
| I don't think a "strong" vs "weak" type system argument
| is particularly valuable here, yes most prevent you from
| inadvertently changing how a particular series of bytes
| is interpreted, but their aggregates do not have any type
| identity besides their own typically. This means you
| cannot typically express and enforce an aggregate's
| covariance or contravariance properties. There may be
| ways to do so, but most do not provide utilities for it.
| Zambyte wrote:
| > I don't think a "strong" vs "weak" type system argument
| is particularly valuable here, yes most prevent you from
| inadvertently changing how a particular series of bytes
| is interpreted [...]
|
| I think that interpretation of the "strong" vs "weak"
| scale is a valuable one within the context of the blog
| post. The post is at least partially about how type
| systems can help the programmer by making them aware of
| certain kinds of errors (it is also about when: static vs
| dynamic).
|
| My understanding of the terms covariance and
| contravariance are a bit shaky. Could you provide an
| example in another language that you think cannot be
| expressed using the provided utilities of most Lisp's?
|
| You also mentioned that you don't think most Lisp's have
| "expressive" type systems. What do you mean by that? When
| I think of a type system as being expressive, I think of
| it as having explicit rather than implicit types, which
| is unrelated to the issue of strongly vs weakly typed and
| static vs dynamic types. Do you mean more like how you
| can describe / constrain the relationships between types
| in certain strongly typed languages?
| packetlost wrote:
| > I think that interpretation of the "strong" vs "weak"
| scale is a valuable one within the context of the blog
| post. The post is at least partially about how type
| systems can help the programmer by making them aware of
| certain kinds of errors (it is also about when: static vs
| dynamic).
|
| Sure, agree. That's also the real point: type systems
| primarily exist to make semantically impossible
| computations unrepresentable in the language (at least,
| without some extra song and dance). To this end, Lisps
| have rather lackluster type systems, but they don't try
| to encode much of the languages semantics into a type
| system.
|
| > My understanding of the terms covariance and
| contravariance are a bit shaky. Could you provide an
| example in another language that you think cannot be
| expressed using the provided utilities of most Lisp's?
|
| The wikipedia article on the topic is a great source: htt
| ps://en.wikipedia.org/wiki/Covariance_and_contravariance_
| ...
|
| I'm actually _mostly_ concerned with type invariants (ex.
| List[int]), which don 't really have much for
| representation in Lisps from what I've seen. Further, see
| above about using types to make compile-time
| assertions/checks about the behavior at runtime.
|
| > You also mentioned that you don't think most Lisp's
| have "expressive" type systems. What do you mean by that?
| When I think of a type system as being expressive, I
| think of it as having explicit rather than implicit
| types, which is unrelated to the issue of strongly vs
| weakly typed and static vs dynamic types. Do you mean
| more like how you can describe / constrain the
| relationships between types in certain strongly typed
| languages?
|
| "Expressive" is a nothing word that doesn't have concrete
| meaning in-context, similar to "strong" type system. That
| being said, I would say Rust, OCaml, and TypeScript have
| expressive type systems: the behavior of the language is
| largely encoded as types. The implicit vs explicit nature
| of types is not super consequential IMO, it has more to
| do with how you primarily represent semantic meaning. In
| lisp, it's symbols. In Rust, it's traits, enums, and
| structs (+ the affine types, but that's not relevant
| here).
| gpderetta wrote:
| Why dynamic typing is required for metaprogramming? D
| (and rust and c++ to a significantly lesser extent) for
| example has extremely strong metaprogramming capabilities
| while being statically typed.
| packetlost wrote:
| I didn't say it was required, I said it hurts it in Lisps
| case. One of Lisps strongest features is extreme
| flexibility and homoiconicity. Strict typing would make
| it clunkier, though maybe it's worth it for some
| scenarios.
| PrimeMcFly wrote:
| In my experience whenever you put effort into making a post
| like this, outlining the common arguments you hear and your
| attempt at refuting them, people don't really pay attention
| and will just repeat the arguments you already addressed,
| ignoring your refutations.
| insanitybit wrote:
| Hey, I hear you, and I _commend_ you for your good faith
| position of "I want to hear both sides". I'm just not there
| anymore. The arguments put forth ("the cost is worth it, it
| makes up for itself", etc) are arguments I've had a million
| times and I just no longer will engage.
| junon wrote:
| Same here. Been doing this for too long that I refuse to
| even bother anymore.
| tasn wrote:
| Oh, apologies, I misread your comment. I thought you were
| saying that you won't engage in this discussion because of
| my strong stance on the topic. I'm a big fan of "Strong
| beliefs, weakly held".
| stratigos wrote:
| Youre missing the perspective of a business owner and
| operator that has to hire many people with diverse patterns
| of thoughts and beliefs who will most likely work for their
| organization for less than 24 months.
| AlanYx wrote:
| If you have a considerable amount of staff turnover, strong
| typing is a godsend for a large codebase.
|
| Having an order of magnitude more unit tests is another
| option, but that undermines the alleged "less code" benefit
| of weak typing.
| randomdata wrote:
| _> I just don 't understand why anyone would ever choose not
| to use types._
|
| Is there a language out there that gives you that choice?
|
| I expect you mean choose not to use strong static typing as
| per the original piece? Compatibility is a pretty good
| reason. I'd like to see Javascript die in the fiery pits of
| hell as much as the next guy, but its positioning means it is
| almost inevitable that some system will make it the only
| reasonable choice for you to choose if you want to build for
| that system.
|
| Typescript doesn't help. It adds static typing, but not
| strong typing.
| junon wrote:
| Python and PHP both have type hints that are natively
| ignored by the language if present, but can be checked if
| you have enough of them, if that's what you mean.
| randomdata wrote:
| No, I mean it lacks strong typing. C and C++ also lack
| strong typing even with static typing being a core
| feature and checked at compile time.
| junon wrote:
| There's no agreed upon definition of "strong" vs "weak"
| so you'll have to elaborate a bit.
| randomdata wrote:
| The only other use I'm familiar with where strong types
| are used to describe the equivalent of static types, but
| we've made clear distinction between the two here. What
| other definition is there?
|
| Usually: A strong type system does not allow types to
| change after being established. A weak type system allows
| types to change. This is also described in the original
| article.
| 1-more wrote:
| How is that different from static typing?
| SkyMarshal wrote:
| My personal notion of a strong type system is one built
| around function type signatures.
|
| In order to have that, you need static typing of
| variables and constants, like most statically typed
| imperative languages have. But you also need a method to
| specify required input types and expected output types of
| all functions.
|
| In a purely functional language like Haskell where there
| are _only_ functions, and functions are first class and
| can be both inputs to or outputs from other functions,
| then the entire operation of the program is encapsulated
| in its function type signatures.
|
| The entire flow of data and logic through the program can
| be type-checked by the compiler, and function
| implementations checked against their type signatures.
| AnimalMuppet wrote:
| C++ has casts. I don't regard those as making it a "weak"
| type system. I regard it as "strong type system with
| escape hatches", which is not the same thing. A strong
| type system should not be a straightjacket. (Languages
| that try to make types bulletproof tend to get used less
| than languages that allow escape hatches, and rightly so.
| The language designer never knows what the union of all
| use cases will be. Good language designers know that the
| user may have a case the designer didn't think of, and
| allow some flexibility to hopefully handle it.)
| zabzonk wrote:
| >A strong type system does not allow types to change
|
| so... like in c++?
| neverartful wrote:
| No. C++ does allow types to change. That's exactly what
| casts are for.
| zabzonk wrote:
| no. c++ allows you to convert a value of one type into a
| value of another type (in a very limited number of cases)
| but you cannot change the type of an object.
| gpderetta wrote:
| You can't change the type of an object in C++ so I'm not
| sure how your definition applies.
|
| Generally "strong" vs "weak" typing[1] is an ill-defined
| an mostly useless definition.
|
| [1] as opposed to static vs dynamic or safe vs unsafe.
| syndicatedjelly wrote:
| What about with type conversion?
|
| https://en.cppreference.com/w/cpp/language/explicit_cast
| gpderetta wrote:
| Casts don't change the type of an object. They might
| create a new object of another type from the first one.
|
| edit: I guess what you want to say is that implicit casts
| make a type system weak. But even there there is plenty
| of wiggle room: I think that everybody agree that
| implicitly converting the string "1" to an integer is bad
| (which is not allowed in C++). Narrowing conversions are
| arguably bad (they are sometimes allowed in C++), but
| some other implicit conversions are hard to argue against
| (int to long for example, or derived to base).
| nyssos wrote:
| > A strong type system does not allow types to change
| after being established. A weak type system allows types
| to change.
|
| For dynamic types, sure, that's a reasonable enough
| definition. But it doesn't really make sense for static
| types: they're attached to expressions in your source
| code, not runtime values.
| pavlov wrote:
| C++ lacks strong typing? I'm curious what the type system
| is missing to qualify.
|
| Or do you mean that the C-based escape hatches like
| casting pointers make the type system inherently weak?
| You don't have to use them though...
| JonChesterfield wrote:
| C++ has chosen a special place in the hellscape of
| language design by allowing you to silence the compiler
| using casts, where almost anything you do with the
| resulting object is undefined behaviour no diagnostic
| required.
|
| Said UB is observationally indistinguishable from
| miscompilation under some toolchains under some
| optimisation controls.
|
| It also has various bolt on weirdness like const doesn't
| mean the thing won't be changed by some other pointer so
| you can't constant propagate based on it, unless it's
| written on the global, at which point attempts to mutate
| it anyway may succeed under the usual UB challenges.
|
| Maybe that's a "strong" type system, but you'd only
| define it like that if you started by taking C++ as
| axiomatically reasonable.
| robertlagrant wrote:
| You don't have to make type errors either :-)
| AnimalMuppet wrote:
| Sure. But you have to deliberately use a cast; people
| rarely make deliberate type errors.
| prewett wrote:
| Static typing is already quite a help, as it makes whole
| categories of errors compile-time errors.
|
| > I'd like to see Javascript die in the fiery pits of hell
| as much as the next guy
|
| Part of the problem is that some of those "next guys" don't
| have the experience and/or vision to realize that it needs
| to die. Perhaps we should emulate Cato in our subsequent HN
| posts:
|
| And furthermore, I consider it necessary that Javascript be
| replaced with WebAssembly so that we can use well-designed
| languages in the browser.
| ndr wrote:
| Consider reading/watching Rich Hickey's talk Effective
| Programs [0][1] and Maybe Not [2][3]
|
| In [0] in particular there're slides 22/23, here is part of
| the transcript but makes more sense with the slides on:
|
| > And you can call them problems, and I'm going to call them
| the problems of programming. And I've ordered them here [...]
| I've ordered them here in terms of severity. And severity
| manifests itself in a couple of ways. Most important, cost.
| What's the cost of getting this wrong? At the very top you
| have the domain complexity, about which you could do nothing.
| This is just the world. It's as complex as it is. > > But the
| very next level is the where we start programming, right? We
| look at the world and say, "I've got an idea about how this
| is and how it's supposed to be and how, you know, my program
| can be effective about addressing it". And the problem is, if
| you don't have a good idea about how the world is, or you
| can't map that well to a solution, everything downstream from
| that is going to fail. There's no surviving this
| misconception problem. And the cost of dealing with
| misconceptions is incredibly high. > >So this is 10x, a full
| order of magnitude reduction in (?) severity before we get to
| the set of problems I think are more in the domain of what
| programming languages can help with, right? And because you
| can read these they'll all going to come up in a second as I
| go through each one on some slide so I'm not going to read
| them all out right now. But importantly there's another break
| where we get to trivialisms of problems in programming. Like
| typos and just being inconsistent, like, you thought you're
| going to have a list of strings and you put a number in
| there. That happens, you know, people make those kinds of
| mistakes, they're pretty inexpensive.
|
| [0] Video: https://www.youtube.com/watch?v=2V1FtfBDsLU
|
| [1] Slides and transcript: https://github.com/matthiasn/talk-
| transcripts/blob/master/Hi...
|
| [2] Video https://www.youtube.com/watch?v=YR5WdGrpoug
|
| [3] Slides and transcript https://github.com/matthiasn/talk-
| transcripts/blob/master/Hi...
| bcrosby95 wrote:
| I don't use dynamically typed languages because they're
| dynamically typed. I use them for other reasons and they happen
| to be dynamically typed.
|
| I'm not going to argue that these features are only possible
| because of dynamic typing, but regardless, statically typed
| languages tend not to have them.
|
| Elixir may get "some form" of typing, but it likely won't be
| traditional static typing.
| syndicatedjelly wrote:
| What are those features?
| bcrosby95 wrote:
| STM, REPL, and data driven nature of Clojure. I know most
| people don't use STM in Clojure, but I find it to be a
| killer feature for some projects. Combined with pervasive
| immutability and it enables concurrent designs that are
| very difficult to pull off in other languages.
|
| For Elixir, the concurrency model and supervisor trees.
| It's a perfect fit for some problems, and in general as a
| small company, the projects we use Elixir on greatly
| simplifies our production environment which is always a
| win.
|
| Most of my focus when designing a project is to enable
| people with less experience than me to contribute in a bug-
| free fashion in the face of concurrency and parallelism.
| Sometimes that involves picking a funny language, sometimes
| it doesn't.
| AlchemistCamp wrote:
| This is a very arrogant and dismissive attitude to take.
| Consider that both pg and DHH prefer dynamic typing. Maybe you
| can think less of them as devs, but what each built is
| undeniable.
|
| What have _you_ built or added to the field that justifies such
| a lack of tolerance of those who don't subscribe to your point
| of view?
| insanitybit wrote:
| I reject the idea that pg/DHH should be treated with any
| authority here, and I reject the idea that I need to prove my
| authority to you.
|
| That said, yes, of _course_ my post is arrogant and
| dismissive. I am outright saying I won 't engage in a
| conversation. I'm comfortable with that.
| fsdjkflsjfsoij wrote:
| This is basically where I am at. Most libraries and
| applications are trivially typed even in languages with
| relatively poor type systems like Go and Java. The necessity,
| or even benefit, of weak and/or dynamic typing is extremely
| rare and most languages have workarounds or escape hatches for
| those exceedingly rare cases.
|
| Dynamic typing also makes a ton of optimizations basically
| impossible and even after monumental efforts languages like
| Javascript are still quite slow, inconsistent and memory
| inefficient outside of trivial benchmarks.
| vasergen wrote:
| > Javascript are still quite slow
|
| Can you describe your usecase for which JavaScript is slow?
| There are many languages that are slower than js like python
| or elixir, but they are doing just fine, that's why I won't
| agree that js is slow, but sure there are cases for which js
| just wasn't designed, and any CPU intensive task will be
| slow, but there are ways to get around it as well.
| diggan wrote:
| > Javascript are still quite slow, inconsistent and memory
| inefficient outside of trivial benchmarks.
|
| I thought this meme was dead already. Of course, you might
| not be able to squeeze out the same amount of performance
| compared to a brilliantly written C or Rust program, but for
| what it is, JavaScript is pretty damn fast already.
|
| DOM manipulation on the other hand, is still a very common
| bottleneck people come across when writing typical JavaScript
| code.
| fsdjkflsjfsoij wrote:
| > but for what it is, JavaScript is pretty damn fast
| already.
|
| It's fast compared to other dynamically typed language
| implementations but it's still very slow compared to
| basically all of the popular statically typed languages.
| wilde wrote:
| JustJS would like a word https://www.techempower.com/benc
| hmarks/#section=data-r20&tes...
| fsdjkflsjfsoij wrote:
| Trivial benchmarks where all of the significant data
| structures and networking are done in C++ and the tiny
| amount of Javascript is just passing some strings around.
| I guess it's "fast" if you can restrict yourself to
| little more than hello world where you do nothing more
| than pass a few strings to functions written in faster
| languages.
|
| Notice that in the Java, C#, Go, Rust, Swift or Ocaml
| benchmarks almost all of the underlying data structures
| and much of the networking stack are built in the
| respective language. This is not possible with
| Javascript, Python, Ruby etc. because it would be
| ludicrously slow and extremely memory inefficient.
| cogman10 wrote:
| > It's fast compared to other dynamically typed language
| implementations
|
| true
|
| > it's still very slow compared to basically all of the
| popular statically typed languages.
|
| Not true.
|
| The main slowdown for javascript (AFAIK) is the checks
| the optimizer has to put into place to ensure the
| assumptions it's made about the type are still valid. If,
| however, those assumptions are valid then javascript ends
| up emitting pretty much the same assembly that you'd see
| for and highly optimized statically typed language. In
| fact, there are some circumstances where it can beat a
| language like C++ or Rust due to the fact that it has to
| incorporate runtime information into optimizations.
|
| With C++ or rust, if you add dynamic dispatch, unless you
| are doing PGO and whole program optimization, you are
| pretty much sunk with 2 memory lookups on every function
| call. This is the case where javascript can end up
| beating C++/Rust.
|
| (All of this is talking about hot code after warmup.
| During the initial execution javascript will almost
| certainly always be slower).
|
| Part of the proof of this was asm.js, the precursor to
| wasm. V8 at the time it was introduced could execute
| asm.js nearly as fast as what firefox could do with it's
| optimized asm.js compiler. That is, when you stripe out
| all the actions that make javascript slow, it very often
| ends up being just as fast as a compiled language.
|
| What stuff ends up making it slow? Generally speaking,
| stuff that makes the types unpredictable (adding fields,
| removing fields, sending in a number and a string and
| expecting the VM to be able to handle both).
|
| You can see a lot of this writeup around the discussions
| about why Dart was originally "optionally typed".
| Basically, the entire selling point to make dart fast was
| simply to remove the abilities to dynamically change
| types like you have in javascript. With that, the VM
| authors at the time were capable of making a VM that's
| every bit as fast as what Java has.
| gpderetta wrote:
| > With C++ or rust, if you add dynamic dispatch, unless
| you are doing PGO and whole program optimization, you are
| pretty much sunk with 2 memory lookups on every function
| call. This is the case where javascript can end up
| beating C++/Rust.
|
| GCC at least is capable of speculative devirtualization
| by using local heuristics, without PGO. And of course it
| is capable of devirtualizing in many cases when the
| knowledge actual type can be constant-propagated.
|
| Also note that the vast majority of calls are not dynamic
| in C++ (as opposed to most dynamic languages), so
| devirtualization is significantly less impactful.
| fsdjkflsjfsoij wrote:
| > That is, when you stripe out all the actions that make
| javascript slow, it very often ends up being just as fast
| as a compiled language.
|
| ok...
|
| > In fact, there are some circumstances where it can beat
| a language like C++ or Rust due to the fact that it has
| to incorporate runtime information into optimizations.
|
| People used to make the same claim about Java and in
| every single example I've ever seen the Java/Javascript
| is extremely optimized, performance isn't consistent
| across VM versions, and the C++/Rust is extremely naive
| (usually allocating unnecessarily and not using arenas in
| hot paths that are allocation heavy).
| PH95VuimJjqBqy wrote:
| absolutely spot on, there was a time when Hotspot was
| going to bring Java to the promised land.
|
| It never happened.
| PH95VuimJjqBqy wrote:
| I think what cracks me up about this conversation is that
| it's an almost verbatim repeat of a conversation I had on
| reddit a few weeks ago.
|
| There's a certain segment of the developer population
| that I don't think realizes just how fast C and C++ are.
| Javascript is _relatively_ fast when compared to other
| dynamic languages, but not when compared to C, C++,
| FORTRAN, etc.
| da4c30ff wrote:
| The take I have is that with a dynamically typed language you
| still have a static analysis step. It's just that the
| analysis happens in your and other developers' brain and it
| is objectively worse. I honestly can't think of a single
| thing in favor of dynamic typing.
|
| I write Clojure in my day job and it's insane how often we
| have issues where it would have been immediately caught by a
| static type check.
| waffletower wrote:
| May I interest you in some unmentioned static analyzer
| possibilities for Clojure: https://github.com/clj-
| kondo/clj-kondo https://github.com/jonase/eastwood You seem
| dissatisfied with Clojure in your day job -- I am sure that
| there are others that would be happier in your situation.
| da4c30ff wrote:
| I'm aware of these, but thank you nevertheless. Clojure
| has plenty of nice things balancing the scales, so it's
| not all pain and misery!
| stefcoetzee wrote:
| I'd love to learn more. Are you part of a large team
| (enterprise or SMB, whatever you can share)?
|
| How have you experienced using Type Clojure, spec, Malli,
| etc. to determine correctness?
|
| I've only worked on solo projects with Clojure, with most
| of it fitting into my head. I imagine with teams of size N
| > 1 things can change quite a bit.
| [deleted]
| jerf wrote:
| There's a temporal component to the argument. Strong typing in
| the 1990s wasn't very good. Dogma at the time resulted in very
| rigid designs. The verbosity of it all was staggering.
| Incorrectly-used Hungarian notation ran rampant and made
| everything hard to read while still not helping anything [1].
| The costs were a lot higher than it is today and the benefits a
| lot less.
|
| Nowadays, the static typing is _much_ nicer, with both higher
| benefits and lower costs, and it makes the costs /benefits
| analysis much more likely to come out in favor of static types.
|
| In the late 1990s when I was cutting my teeth, I did a lot of
| Python, and I was almost 100% dynamic language until ~2015. In
| hindsight, I might do the same again even if thrust back in
| time. There just isn't a _great_ static option back then. (I 'm
| not saying 2015 is the year it became practical, I'm saying
| that's when _I_ finally moved into static languages. 2010-2015
| or so I was in Erlang, doing things that most other languages
| couldn 't do at the time, so that forced me into a dynamic
| language. C# was looking pretty good in that time frame too, it
| just wouldn't have run the systems I had on anything like the
| resources I had at the time. It could probably easily do it in
| 2023 though.)
|
| Now I even prototype in static systems, and it's a better
| experience than prototyping in Python was. Like, by quite a
| lot, honestly. In the end, I don't find it that much of an
| impediment to make sure that if I want to call a method on a
| thing, that the method actually exists.
|
| Dynamic typing will never disappear; there's a certain small
| size of task for which it'll always be more advantageous than
| static typing, and while said tasks may be small, there's a lot
| more of them than there are large tasks, so it's a completely
| valid and sizable niche. But I do think over the next 10-20
| years we're going to see the "scripting" languages return back
| to "scripting" and away from "systems".
|
| I think that in the end, the dynamic scripting languages being
| used for large tasks will be seen as a reaction to a
| misdiagnosis of the problems in the 1990s. The code was
| atrocious in the 1990s not because it was statically typed, and
| therefore the solution is to go dynamically typed. The code was
| atrocious in the 1990s because it was _poorly_ statically
| typed, and the solution was to get better. That said, "getting
| better" did take a long time, and for many legitimate reasons.
|
| (Much ink is spilled on the so-called rapid pace of
| technological innovation in our industry, but programming
| languages move on decadal scales. Programming languages still
| have only barely grappled with a multicore world, and haven't
| grappled with a heterogenous computing world at _all_ (GPUs on
| one end, efficiency cores on the other). Things are not always
| in as much motion as we fancy.)
|
| [1]: Particularly, Hungarian notation is supposed to
| _supplement_ the type, not just reiterate it. If you 're in a
| language where you can't easily declare "a width is an int",
| then Hungarian notation suggests calling a width variable
| something like "wdthDialog", so that you stand a chance of
| noticing that you passed a "hghtDialog" in the wrong place. But
| the way it was used a lot of the time is you got "u16Width"
| instead, where u16 meant unsigned 16 bit int... but that's
| already in the type. Using it that way just adds an extra layer
| of hierglyphicness to the already ugly code. One of the several
| innovations that made static typing languages more feasible is
| that in most languages designed in the last couple of decades,
| you can declare something like this with something like "type
| Width int", and then you don't need to label any variables with
| it at all, the compiler enforces it.
| justincredible wrote:
| [dead]
| pfdietz wrote:
| Strong static typing is useful in the environment where the
| code is not adequately tested. That's because tests adequate to
| make the code bulletproof will also detect the problems strong
| static typing could detect, rendering SST superfluous.
|
| So, how often is poorly tested code out there? From the
| popularity of strong static typing, it must be ubiquitous.
| d3w4s9 wrote:
| No. It is useful in almost every environment other than
| things like REPL. I can write TypeScript for hours without
| writing any tests, run it and fix a few minor logic bugs and
| code is production level, which is great for prototyping. No
| chance with plain JavaScript without typing -- it would be at
| least a day or two and I would constantly run into stupid
| typos or other errors that can only be found at runtime.
| sneed_chucker wrote:
| Yeah, big piles of untyped Django spaghetti need a behemoth
| suite of integration tests in order to remotely approach the
| sort of runtime guarantees that typed languages give you for
| free.
|
| When you use a typed language, you can use your integration
| tests to actually verify business logic, exception handling,
| etc. instead of having to write a dozen test cases to make
| sure that doThing(table, index,*kwargs) doesn't blow up when
| 'table' is a list or 'index' is bytes...
| pfdietz wrote:
| If you adequately test your code for logic bugs, you test
| the type correctness _for free_. So, yeah, writing those
| logic tests is hard. But at least they are finding bugs
| that static type checking never will (absent the
| unrealistic scenario of proving your program correct via a
| type system.)
|
| (It won't find latent bugs that can't currently be
| exercised, so the testing can't be one and done.)
| _dain_ wrote:
| you can't ensure that you hit every possible case in your
| test suite. type errors can still slip through in
| production, just like logic bugs do. it happens all the
| time in real-life code. that "adequately" is a no-true-
| scotsman.
|
| if you use a static type system you can _guarantee_ there
| will be no type errors at runtime. why on earth wouldn 't
| you choose that? you can still write logic tests!
|
| and when you leverage the type system to make illegal
| states unrepresentable, you can make certain classes of
| logic error impossible as well. some of your tests become
| tautologies and you can delete them.
| pfdietz wrote:
| You are assuming type errors are caught by tests
| explicitly written to detect them, as opposed to being
| found by other kinds of tests. For example, property
| based tests, with automated generation of inputs to a
| program or module, don't explicitly test for type errors,
| but are still (in my experience) quite good at hunting
| them out.
|
| What testing cannot find are latent errors not exercised
| by the program. Do I care about these, though? Arguably
| these would be found by testing internal interfaces and
| elimination of code not reachable by tests.
|
| The general argument I am trying to make is that the
| marginal value obtained by strong static typing declines
| as testing increases, and that in the limit goes to zero.
| If a program is adequately tested, is it still worth
| doing? This is not clear to me, and the arguments given
| here have not convincingly demonstrated that it is worth
| it.
|
| Also: if you find yourself in a situation where strong
| static typing seems useful, you should be alarmed. It
| means you aren't testing your code very thoroughly.
| _dain_ wrote:
| _> You are assuming type errors are caught by tests
| explicitly written to detect them, as opposed to being
| found by other kinds of tests._
|
| I am not assuming that.
|
| honest question: what language do you have in mind when
| you think "static types"? your perspective is so starkly
| different to mine, you seem to be operating under totally
| different assumptions about what types can and can't do.
|
| I mean this sentence:
|
| _> Also: if you find yourself in a situation where
| strong static typing seems useful, you should be alarmed.
| It means you aren't testing your code very thoroughly. _
|
| is just baffling to me. it's so self-evidently absurd
| that I can't even argue against it. what is there even to
| say?
|
| have you even used a modern statically typed language,
| with type inference, generics, null safety, algebraic
| data types, pattern matching, etc? I cannot imagine
| trying to maintain a big codebase without them. they
| don't slow me down, they speed me up. they aren't just
| about catching trivial int-instead-of-string bugs, they
| are are core tool for _modelling_ data and business
| logic. they let me define problems out of existence (see
| e.g. this series of posts
| https://fsharpforfunandprofit.com/posts/designing-with-
| types... for an introduction).
|
| and then there's rust and newer-generation languages with
| borrow checkers and affine/linear types, ruling out
| entire classes of memory and concurrency bugs ... your
| test suite cannot rule out data races, but rustc sure
| can.
|
| you are making the same arguments people were making in
| the 2000s when most static languages sucked because they
| didn't have these features. I don't want to go back to a
| time before sum types.
|
| _> What testing cannot find are latent errors not
| exercised by the program. Do I care about these, though?_
|
| you should, because in production your program must
| endure orders of magnitude more variety in inputs,
| uptime, and runtime conditions than the test suite can
| exercise. it can and will get into weird states you
| didn't anticipate. yes, you can fuzz, yes you can
| property test, I know all about that. those things are
| good. but I don't get why you wouldn't _also_ use a
| static type system to _provably_ rule out classes of
| problem across _all possible_ code paths. why settle for
| less?
| xmcqdpt2 wrote:
| High test coverage is useful in the environment where the
| code is not adequately typed. That's because static types
| adequate to make the code bulletproof will also detect the
| problems unit tests could detect, rendering high unit test
| coverage superfluous.
|
| So, how often is poorly typed code out there? From the
| popularity of test coverage tools, it must be ubiquitous.
| pfdietz wrote:
| The turned-around argument has a problem: testing should
| reveal type bugs, but static typing (of the kind typically
| discussed for mainstream languages) can't reveal non-type
| bugs.
|
| In a situation where extreme levels of testing occurs, the
| extra assurance from strong typing is minimal. In a
| situation where strong typing is enforced, extra testing is
| still very useful.
| user3939382 wrote:
| Integration tests are different, but I tend to believe that a
| strong enough type system should be able to negate the need
| for unit tests completely.
|
| If anyone can think of something a unit test could test for
| that an arbitrarily* complex/strong type system couldn't I'd
| be interested to hear it. It's possible, I just can't think
| of any.
| bluGill wrote:
| Unit tests and types solve somewhat different problems. You
| can force a unit test to check everything a type system
| does with effort (mostly by throwing wrong types at your
| API and verifying you get an error), but I'm not sure how
| you would use the type system to enforce sort() actually
| sorts. Sure sort can take a listOfFoo and return a
| sortedListOfFoo - but that doesn't verify sortedListOfFoo
| is actually sorted - and in many cases I want an API that
| is find with listOfFoo but should handle sortedListOfFoo as
| well.
| skulk wrote:
| With dependent types you can encode any proposition in
| first-order logic (?). You can indeed define an array
| type that is necessarily sorted. It won't be pretty but
| it's possible.
|
| More info here: https://en.wikipedia.org/wiki/Curry%E2%80
| %93Howard_correspon...
| pfdietz wrote:
| When I say adequately tested, I mean much more than unit
| tests. Unit tests aren't going to give you bulletproof
| code. They don't detect bugs that arise from interactions
| at a higher level.
|
| An arbitrarily complex type system, with dependent types,
| could detect any bug, since it's formally equivalent to
| requiring the program be proved correct. But using such a
| type system is so onerous that I don't know anyone who
| realistically does it in production.
|
| If you wrote such types, you're basically giving a formal
| specification of what the program is supposed to do. That
| could then be used, and likely much more easily, for high
| volume property-based testing.
| _dain_ wrote:
| I like type systems as much as anyone but I can't see how
| your type system will check that sin(pi) == 0
|
| if you have a type system expressive enough to do things
| like that, you've basically got another turing-complete
| layer on top of your existing language, which is itself ...
| dynamically typed.
| yakshaving_jgt wrote:
| > Strong static typing is useful in the environment where the
| code is not adequately tested. That's because tests adequate
| to make the code bulletproof will also detect the problems
| strong static typing could detect, rendering SST superfluous.
|
| Ok, but it's cheaper to not have to write those tests than it
| is to write those tests.
| pfdietz wrote:
| Yes. It's cheaper to have a lower assurance your program is
| correct than to have a higher assurance. The claim I'm
| making is that at the high end, the extra assurance from
| strong static typing becomes minimal.
| yakshaving_jgt wrote:
| > Yes. It's cheaper to have a lower assurance your
| program is correct than to have a higher assurance.
|
| That's quite clearly not what I'm saying.
| ozr wrote:
| Ubiquitous is a good guess.
| soggybutter wrote:
| Good tests only render SST superfluous insofar as the person
| writing the tests is capable of never making a mistake. The
| thing about good static type systems is they don't typically
| make mistakes in the domain they work in. The fact that you
| don't have to muddy your test with a bunch of type checking
| logic and instead focus on the thing actually being tested is
| just the cherry on top.
| dolmen wrote:
| The point of static typing is that the compiler does checks
| before your program even starts. And that avoids to write lot
| of coverage tests that are needed (but usually just ignored)
| with languages that massively use loosely typed data
| containers (variables).
| pfdietz wrote:
| Sure, if you're going to be in an environment where the
| code is going to be bad because of inadequate testing (and
| I admit this is quite common, due to the cost of the
| testing needed), static typing lets it be somewhat less
| bad. It's just important to understand it's a band-aid, not
| a panacea.
| marcosdumay wrote:
| Testing is a bandaid that only pretends to show that your
| code is correct.
|
| Static verification (what includes static types) is the
| real deal.
|
| That said, WTF is there with people insisting that types
| must be either static or dynamic, and that dynamic types
| are useless?
| pfdietz wrote:
| Static typing, as done in mainstream languages, doesn't
| show your program is correct. Is you compiler written in
| a mainstream language correct just because it compiles?
| Of course not. Don't point to academic curiosities with
| dependent types if they aren't actually used. Extensive
| testing, on the other hand, _is_ used in the "real
| world" for assurance.
| marcosdumay wrote:
| Every code out there on the real world is full of
| baindaids and duct tape. Yet, the actual amount varies a
| lot, as does the centrality of the patched things.
| yakshaving_jgt wrote:
| This is the classic "Uncle Bob" style false dichotomy.
|
| Whoever said you can only pick one of the two approaches?
| mejutoco wrote:
| That is a very original take, but I think you have it
| reversed. Typing removes the possibility of _some_ errors.
| Those are tests you do not _need_ to write (you can still
| write them if you want), thus having more time and attention
| to write tests that matter. Typing is a baseline, and
| anything over that baseline you can deal with with tests.
|
| It is like the things you already trust when you code. Let's
| say, that the file system works, that the network stack of
| your OS works, or that the cpu works. You can rely on them to
| use your time for the things that matter. This is a much
| better model than simply testing everything yourself since,
| as the tests number increase, any change to the codebase
| involves more and more test changes.
|
| > Strong static typing is useful in the environment where the
| code is not adequately tested. That's because tests adequate
| to make the code bulletproof will also detect the problems
| strong static typing could detect, rendering SST superfluous.
|
| Your logic is the same as follows: seat belts are useful in
| an environment where drivers are not driving adequately.
| That's because adequate drivers will drive in a way to avoid
| any danger that the seat belt would prevent, rendering seat
| belts superfluous.
|
| Ultimately, the problem is adequate drivers (as in described
| above) or bulletproof tests do not exist, they are just a
| concept. A test can prove the presence of an error, not the
| lack of errors, and the argument only works in absolutes.
| pfdietz wrote:
| You seem to be thinking that testing for type errors is
| something additional to general testing. It's not. With
| sufficiently strong logic testing, the testing for type
| errors comes along for free.
|
| The analogy with driving doesn't make much sense. After
| all, accidents sometimes happen without the driver being to
| blame, and the marginal cost of putting on a seat belt is
| very low.
| mejutoco wrote:
| With sufficiently adequate drivers seatbelts are
| superfluous indeed.
|
| Apart from an analogy is a template of your argument. It
| is the logic of the argument itself.
|
| Errors also happen sometimes without type systems being
| to blame (they only catch a subset of errors).
|
| The marginal costs of a type system is usually very low
| too, so it seems to be a great fit.
| Kuinox wrote:
| Tests is testing your program against samples, where strong
| typing make your program incorrect on a whole spectrum of
| samples.
| ShellfishMeme wrote:
| Strong types aren't just a correctness guarantee, they also
| help to discover structure and interfaces that previously
| were implicit.
|
| If a developer can jump into an unknown part of a codebase
| and quickly see that following a certain structure will
| automatically make their code work for them without needing
| to read all the code first and double checking if it's just a
| random convention versus a strict interface so they don't
| reinvent the wheel or build code that doesn't fit in with the
| existing structure, then that's worth a lot and something you
| cannot simply cover with tests.
| brightball wrote:
| I'm firmly in camp "it depends" but it was nice almost talking
| to you. :-)
| c048 wrote:
| People that still want to try and fight it either:
|
| - Use notepad for development (don't laugh, I've actually
| encountered a dev who's choice IDE was notepad).
|
| - Never worked with more than 1 person on a project.
|
| - Never worked on anything but tiny projects.
|
| - Never re-opened a project after having worked on a different
| project for several weeks.
| Qwertious wrote:
| You should legitimately try a project in notepad. Not
| Notepad++, specifically Notepad. Probably a very short
| project, but you should give it a shot. It'll give you a bit
| of a perspective. And some real appreciation for Notepad++.
| bluGill wrote:
| I've been forced to use ed (serial connection to an
| embedded device that didn't support TERM), what does
| notepad give?
| manicennui wrote:
| This is the sort of position that is baffling to me. Software
| engineers claim to be very logical, but this boils down to a
| preference being stated as some kind of objective truth. Show
| the evidence (not anecdotes) that static typing gives benefits
| that are worth the cost. My anecdotal evidence is that I rarely
| come across problems in production code that would be solved by
| static typing and people make the same sorts of logic mistakes
| in languages like Java and Typescript.
| manicennui wrote:
| Arguably, nullability and mutability are issues that cause
| far, far more issues than dynamic typing.
| tubthumper8 wrote:
| Null reference errors are examples of errors that can be
| caught before runtime by a static type system. The fact
| that static type systems like Java don't catch this is
| evidence that static vs. dynamic is not a binary - some
| static type systems are better than others.
| bitblender wrote:
| I don't consider it productive to be personal about technical
| topics. It's best to divorce yourself and the other party from
| the issue to limit as much bias as possible. You don't need to
| worry about the good-faithness of an objective, egalitarian
| discussion. It's never truly objective, but you can at least
| catch yourself saying things like "I might think less of you as
| a developer" and recognize that's a preconceived notion. In
| some cases, it may be turn out to be accurate, but it's
| definitely not always. Dynamically typed languages have had an
| important role historically in software. We should not
| categorically denounce people who prefer it as lesser
| developers. I also generally prefer static types.
| mvdtnz wrote:
| I think you're being a bit too sensitive, and it's not
| personal. Someone is espousing a (bad) technical opinion
| about their field of work, it's not unreasonable to say you
| respect them less in their field of work. That's not
| personal.
|
| It's like if you met a builder who refused to use a hammer
| and insisted on bashing nails in with the back of their
| drill. It's not "personal" to say you'd respect that person
| less as a builder, regardless of how much you'd enjoy having
| a drink with them.
| bitblender wrote:
| It is "personal" if you attach someone's technical opinion
| to broader implications about their own competence. If you
| disagree with a technical opinion, say so and move on,
| there is no reason to even discuss someone's own personal
| skillset, experience, or value as a developer. It's a silly
| fallacy to automatically label people who disagree with you
| as incompetent. All it does is foster bias and stifle
| actual discussion. The responses to this post are evidence
| that this is not as cut and dry as the original posts
| suggests, so I suggest we try our best not to cover our
| ears and embrace tribalism just because we think less of
| someone's opinion. I don't think I'm being oversensitive by
| saying this is unproductive dogmatism. It is my honest
| opinion, yet I do not extrapolate to mean anything about
| the proponents' value as a developer. Unconscious bias is a
| pervasive problem for everyone, especially when it comes to
| binary holy wars like static vs. dynamic types. This is
| more akin to a builder who uses a nail gun rather than a
| hammer. Hammer enthusiasts can either acknowledge that both
| approaches have tradeoffs or they can petulantly insist
| that people who don't use their methods aren't "real"
| builders.
| mvdtnz wrote:
| I'm sorry but this is a discussion about their
| competence. You can't separate someone's opinions on
| technical topics from their competence in the very
| technical field you're discussing. If a cartographer has
| the "opinion" that the world is flat then that directly
| speaks to their competence as a cartographer.
| bitblender wrote:
| For starters, "the world is flat" is falsifiable and
| trivially disproven with evidence. "Dynamic types are
| better" is neither of these. If you're going to pin
| someone's professional value to a single technical
| opinion, you should at least be able to back it up with
| data.
| insanitybit wrote:
| I explicitly said "as a developer" because it's not a
| personal judgment. You can be a good person and also have a
| terrible take as a software engineer.
|
| > We should not categorically denounce people who prefer it
| as lesser developers
|
| I don't think you've justified this point. I'm comfortable
| with my position on this.
| bitblender wrote:
| Again, I don't mean "personal" in the sense that you are
| making a statement about someone's worth as a person. It's
| "personal" because you extrapolate information about an
| individual person's technical skills from a single opinion
| than you have any real factual justification to do so.
| People will always find ways to defy your preconceived
| notions.
| PH95VuimJjqBqy wrote:
| to add, I agree with you mostly.
|
| I don't necessarily think it makes someone a "lesser
| developer" if they prefer untyped languages, but I DO think
| they've either had to maintain anything long term or it
| stayed relatively small.
|
| Whether that makes them lesser or not isn't really for me
| to say, but I can say I'm definitely on board with the idea
| that types increase productivity the longer a system is
| maintained. Unless used poorly, types don't automatically
| mean you use them well, but they make it a hell of a lot
| easier to do the right thing.
| eduction wrote:
| What you say is true, but it's also true that the person
| you are replying specifically made their remarks about
| productivity - you're both talking about what is best at
| work.
|
| It seems reasonable to argue that statements that you won't
| even discuss X any more and would rather judge the person
| as less competent professionally are unproductive. Not
| saying I agree, btw. But it does seem like a pretty basic
| point. One of you is talking about preserving your sanity
| and the other about output. It's not necessarily a
| disagreement even.
| PH95VuimJjqBqy wrote:
| > any more and would rather judge the person as less
| competent professionally
|
| That is absolutely NOT what the other poster said. They
| said they _MAY_ judge them that way.
| eduction wrote:
| Fair point, you're right!
|
| I still think it's reasonable to argue that's not a
| "productive" approach, but like I said, that's not my own
| opinion, I just think it's a reasonable argument.
| HideousKojima wrote:
| Nah, someone opposed to typing is either a shit developer
| and/or a madman who codes too clever by half mad shenanigans
| that take advantage of the lack of strong typing. I wouldn't
| want to have to maintain or depend on code written by either.
|
| For the very rare cases where a lack of strong typing is
| needed, most languages with strong typing offer ways to
| handle that (i.e. the Object and Dynamic types in C#)
| loup-vaillant wrote:
| Some prejudices _are_ rational. To paraphrase, it would take
| an enormous amount of prior trust and respect before I even
| humour someone trying me to convince me the sky is green with
| a straight face.
|
| Some issues are settled enough that there is no need to
| discus them any further. It is _okay_ to automatically mark
| people on the wrong side of such issues... let's say ill-
| informed.
|
| Static typing, I believe, is close to being one of those
| issues.
| jimbokun wrote:
| If your prejudice prevents you from having a conversation
| with Matz or Jose Valim or Van Rossom or the creators of
| Julia about software development, you may want to
| reconsider your prejudice as a hard and fast rule.
|
| You can't honestly believe no one who likes to develop in a
| dynamically typed language has nothing interesting to say
| about software development?
| mcronce wrote:
| I can't (or, more accurately, _don 't_) believe that, but
| I can certainly believe they have nothing interesting to
| say about the topic of static vs dynamic typing.
| _a_a_a_ wrote:
| I'm very much with you on static typing but you've closed
| your mind with a slam. Please don't.
| lovich wrote:
| An open mind is like a fortress with its gates unbarred
| and unguarded.
|
| It is both useful and allowed to have a certain level of
| belief that won't be crossed without heavy effort. The OP
| didn't even say they were closed to the conversation
| completely, but that a random person with no pre built
| trust isn't going to get the time of day from them to
| rehash the same settled argument.
| _a_a_a_ wrote:
| "Matz or Jose Valim or Van Rossom or the creators of
| Julia"
|
| from memory Matz -> ruby, Valim-> elixir, Van Rossum ->
| python, and 'the creators of Julia' -> julia
|
| Not 'random persons' then
| yetanotherloser wrote:
| To be honest, I think dynamic typing must contain a mind
| trap. Very smart people fall in.
| wredue wrote:
| These people opinions are based on bad information.
|
| Beliefs inform decisions and other beliefs
|
| I disagree with them on a huge number of fundamental
| things in software. Most of their fundaments are claims
| with no evidence. Due to that, I simply do not care about
| what they have to say most of the time.
| scns wrote:
| Python got type hints bolted on. A type system for Elixir
| is being worked on. Dynamic typing was a prerequisite for
| Erlang to enable hot-code-reloading. Julia is can be
| typed for an extra speedup. Stripe built a type checker
| for Ruby called Sorbet.
| adgjlsfhk1 wrote:
| Julia generates fast code without type annotations
| (except for your data types).
| sundarurfriend wrote:
| > (except for your data types)
|
| This confused me for a moment, but I think you mean
| annotating the types of the fields in your `struct`s,
| right?
|
| An addition to that: any non-constant global variables
| (if you must have those) should also be type annotated.
| insanitybit wrote:
| If I have pre-existing respect for someone I will hear
| them about. But the bar for that conversation is high.
| betenoire wrote:
| I'm not sure what is worse, loving dynamic languages or
| having all these pre-existing conditions
| insanitybit wrote:
| Doesn't everyone have those? Like, I'm unlikely to really
| engage with someone about my health unless they're a
| doctor or otherwise have some area of expertise. Or if
| it's just a casual, friendly conversation, to kill some
| time.
| betenoire wrote:
| Everyone has biases. But you aren't describing a bias,
| you are describing a refusal to engage with people below
| you. Speak for yourself, I don't have that.
| insanitybit wrote:
| "Below you" is a bit of an exaggeration, I think. I said
| that I might think less of someone as a software engineer
| if they express an opinion that I think is particularly
| bad. Hardly egregious, in my opinion. I also might not -
| it frankly depends a lot on the situation.
| sixstringtheory wrote:
| We're all humans and life is very complicated with many
| facets. If we all looked hard enough I'm sure we could
| find a person you'd refuse to engage in a debate with
| over their "thing."
|
| But that wouldn't be a wise use of time in my opinion.
| And that's what they're ultimately driving at: we all
| have limited time to expend, so do it in things that
| matter to you. I believe "matters to you" is a bias.
| _dain_ wrote:
| idk about the others but much of Guido's development
| energies the past few years have been spent building
| Python's gradual static typing system.
| SAI_Peregrinus wrote:
| I'd love a dynamically typed scripting language with the
| following two properties: no "import" mechanism to split
| code over multiple files, and no way to execute more than
| (say) 256 lines of at most 128 bytes each in the file.
|
| Dynamic types are nice for quick & short scripts, and
| actively detrimental for anything long and complex. Why not
| enforce that? As soon as it gets so long it doesn't run you
| know it's time to rewrite in a statically typed language.
| Instead all existing scripting languages allow unlimited
| growth in code size, making it easy for programs to grow
| beyond the point where the language is useful.
| gls2ro wrote:
| > Dynamic types are nice for quick & short scripts
|
| A long list of big products and companies are there to
| disagree with this. I am not saying that dynamic is
| better or worse. But saying that dynamic languages are
| only good for quick short scripts is a wrong
| generalization that has not one exception but many
| exceptions.
| kdmccormick wrote:
| I think this is OK as long as you keep your mind open to
| situations that you have not considered.
|
| Imagine someone is working in a relatively niche new
| programming language ecosystem which is dynamically typed,
| allowing the language to have some richness that modern
| type systems don't support. I don't have an example because
| I don't know of any such language in 2023... BUT back in
| the 70s and 80s this would have been Lisp. Lisp couldn't
| have been strictly typed back then because, AFAICT, type
| systems hadn't advanced enough to express the sort of
| metaprogramming that made Lisp unique and awesome. This was
| at a time when most popular languages were strictly typed.
|
| I would hope that you would keep your mind open to whatever
| that maps to in the 2020s.
|
| Now, if someone says "I like JS over TS because types are
| annoying and slow me down", then yeah, I don't have much
| patience for that either.
| digging wrote:
| You make points that seem great to me although I know
| almost nothing about Lisp or 20th century programming.
|
| The thing is, I've yet to encounter a single instance of
| such an argument today. Every single time it ends up
| being "I like JS over TS because types are annoying and
| slow me down". It hadn't even occurred to me that
| laziness and sloppiness weren't the the only reasons to
| write in dynamically typed language.
|
| I suppose what I'm saying is I'm quite interested in
| seeing what kind of evolution some dynamically typed
| language could offer in the future. Although with no
| signs of its coming, I'm going to stick to TS because
| it's objectively better for anything but very small
| projects.
| hansvm wrote:
| TS is an interesting example to pick when trying to argue
| that types are better. You have all the same downsides
| people pick on when arguing against strong, static
| typing, but since the type system isn't sound you still
| can't rely on the input to a function being the type you
| expect (and the problem is worse anywhere you inevitably
| interact at least a little with the JS world outside your
| TS bubble).
|
| At best it's a form of documentation that enables some
| simple linting rules and a bit of jump-to-definition
| magic. Like, that's a benefit (mostly -- I tend to think
| that type signatures implying more guarantees than they
| provide is a recipe for inadvertently relying on
| falsehoods), but it's not as clear-cut of a win as you
| see in other statics/dynamic tradeoffs.
| uoaei wrote:
| It sounds like you have an implicit prejudice against
| those who do not "keep [their] mind open to situations
| that [they] have not considered", since the way you
| phrased your concern is moral in nature. You see it as
| morally bad not to have an open mind in that way.
| mvdtnz wrote:
| As Carl Sagan said: it's good to have an open mind, but
| not so open your brains fall out.
| kdmccormick wrote:
| Yeah, sure, I do in fact think it is virtuous to be aware
| that we don't always have complete information and that
| we should be willing to revise our opinions when new
| information is encountered. Is that controversial?
| uoaei wrote:
| No, no, not controversial. I intended to make it easier
| to understand the point by demonstrating for the more
| literal-minded that using moral language sets up two
| halves of a dichotomy, one preferred to the other, so
| that such prejudices needn't be _personal_ but rather
| merely moral. The difference is of course that which side
| of a moral dichotomy is a choice that can be reversed
| (e.g. making an effort to open the mind) while personal
| matters are immutable in those people.
| monocasa wrote:
| Python fits that niche now. Half the way tensorflow, et
| al work is by doing brain surgery on the AST in a way
| that resembles hey day Lisp's 'even the code is just
| s-expressions, process it as much as you want to the
| point of 80/20ing your way to your own compiler'.
| mikelevins wrote:
| Imagine working on a networked system that uses types to
| make it impossible to express operations that violate
| data security and integrity constraints, and where such
| constraints control whether data is allowed to be read or
| written from or to a given endpoint. Imagine further that
| the types governing permission to read or write depend on
| environmental state that can change at any time--for
| example, as soon as a specific person changes roles, the
| set of ports they are allowed to read and write changes.
|
| The type system enforces those permissions: writing to an
| impermissible destination is a type error. The types
| applicable to an entity are not necessarily knowable at
| compile time; some of them might change at any time.
|
| I had a job working on such a system. It supported a type
| system implemented in Haskell with both static and
| dynamic type disciplines, where values were tagged with
| base types designed to be checked dynamically in
| hardware.
|
| Was the programming language dynamically typed? Yes. Was
| the programming language statically typed? Yes.
| klyrs wrote:
| > To paraphrase, it would take an enormous amount of prior
| trust and respect before I even humour someone trying me to
| convince me the sky is green with a straight face.
|
| Don't venture into tornado country; your doubt may be your
| downfall.
| soperj wrote:
| > To paraphrase, it would take an enormous amount of prior
| trust and respect before I even humour someone trying me to
| convince me the sky is green with a straight face.
|
| But people regularly say the sky is blue, and it's clear as
| day that it's not when the earth has turned and your side
| isn't facing the sun.
| bluGill wrote:
| The sky is still blue, the lack of light means you cannot
| tell, but the color is still there.
| stouset wrote:
| The sky isn't inherently blue. It's essentially
| colorless.
|
| Only due to Rayleigh scattering do we perceive it as
| blue, but that's not due to the absorption and reflection
| of different wavelengths we associate with innate color.
| Note that the color changes depending on the angle of the
| sun, even to the point that it's purple and red at a few
| times during the day.
| quonn wrote:
| Perhaps, only because the sky is blue we perceive blue as
| blue. If the sky were red we would perhaps perceive all
| red like we do blue.
|
| Our perception of the important colors (sky blue, ocean
| blue, vegetation green, ...) probably evolved along with
| our physical needs.
| soperj wrote:
| no... the sky is clear, and it's the refraction of light
| through the atmosphere that's confusing you.
| bluGill wrote:
| As someone who would die without an atmosphere the
| distinction is meaningless.
| soperj wrote:
| you're going to die regardless. The sky still isn't blue,
| which is quite obvious at night, or during sunsets and
| sunrise.
| digging wrote:
| I don't think that's a statement that most would agree
| with. What is the sky? Sure the atmosphere can be called
| blue, but the sky is what's visually above the earth. At
| night, that's black space. The atmosphere is mostly
| transparent at night.
| ilaksh wrote:
| As someone who usually prefers JavaScript over TypeScript but
| has used many typed languages over the years and generally
| finds then easier to work with in a way, I agree that one
| should not pre-judge based on something like that.
|
| But he's just being honest. Many developers have been making
| that judgement for many months or even years.
| bennyelv wrote:
| Amen!
|
| I'm currently responsible for a very large system built in raw
| javascript where function definitions like this one in the
| article: function birthdayGreeting1(...params)
|
| ...are the religion.
|
| It's awful. I hold the people responsible in very little
| regard.
| nkozyra wrote:
| I'm baffled it's even a debate. Who wouldn't want strong
| typing? What's the argument?
| digging wrote:
| Mostly, it boils down to selfishness and "laziness".
| (Although I try to be very careful about that term, because I
| do not believe in it as generally used. I use it here to
| define: an unwillingness to plan ahead and to have to learn
| something new. Not applied as a global personality trait but
| only used in context.)
| throw1234651234 wrote:
| I think this is especially true for line of business
| applications that have the following qualities:
|
| 1. It's simple. Let's not lie, let's not pretend. It's CRUD.
| You can put in K8S, you can add AI, it can be behind an API
| Gateway, you can make it all Event Driven, you can use CQRS for
| every entity because you really, really want to feel clever.
| But it's still CRUD.
|
| 2. Other people are working on it, many other people.
|
| 3. People from other companies are interfacing with it.
|
| So knowing what to expect trumps everything. Types help with
| that. They help a lot.
| iopq wrote:
| There's ONE argument that I'm partial to:
|
| if you get the static type system wrong once, there's no going
| back
|
| Take for example, Rust: mut, Send, Copy, Drop, Debug, dyn have
| all their warts because they are special and you can't fix them
| because you'll break previous code.
|
| In a gradual typing language you could potentially bolt-on your
| own type system as a package where it just runs the type
| checker if you want one. It just so happens people who favor
| these gradual typing systems don't do a good job of creating
| those typing systems because they are not that into types in
| the first place.
|
| But in theory, this kind of a system would let you not worry
| about types when prototyping the system, then put some bounds
| later based on your requirements.
| zare_st wrote:
| I'm not sure what I'm reading here.
|
| Types are integral part of standard programming languages. If
| you mean "types bad" as in BASIC/Javascript variables, then yes
| I fully agree. These languages were never meant to be a
| solution for professional software engineering.
|
| Once a language has proper types, it can be "weak typed" by not
| forcing "strong typing" by being dynamically typed in nature.
| If the language has normal preprocessor support, the static
| type system can be added on the project level. And then in
| essence you get a strong typed environment in a very thin
| programming language such as C.
|
| Let's take a big C or C++ software project, the process behind
| it. Of course, the project is in those languages because it
| requires native opaque pointers and hardware access. The
| project has coding style, it has arbitrary rules. Although
| there is little to stop anyone from making a mess in C or C++
| code there is entire code infrastructure and CI/CD chain around
| it. Lets say the rule is no void pointers without encompassing
| struct that's a type that can be checked via macro system. If
| you wrongly use the type struct, you get stopped by the project
| build. If you go around the rule, you get stopped by a code
| analysis after commit (and get in trouble for doing that).
| [deleted]
| flohofwoe wrote:
| So... about the _strong_ part in 'strong static typing':
|
| Many years ago I thought that it's a good idea for a game math
| library to have separate strong types for 'point' (a location
| in 3D space) and 'vector' (a direction and magnitude in 3D
| space), and allow/disallow certain operations (e.g. 'point +
| vector => point' 'vector + vector => vector', 'point - point =>
| vector', while 'point + point' is illegal).
|
| Sounds absolutely great in theory, but in practice it was a
| royal PITA to work with, but it took me much too long to
| realize this (how can it be such a hassle when in theory it's
| such a good idea!)
|
| I soon went back to a general 4D vector class (where a 'point'
| is defined by .w = 1.0, and a 'vector' by .w = 0.0), and some
| debug-mode runtime validation (which catches things like trying
| to add a point to a point).
|
| Of course strong typing also often makes perfect sense, for
| instance in a 3D rendering API it should be a compilation error
| to provide a texture-handle where a buffer-handle is expected,
| but after this experience with points vs vectors (which
| should've been a classic showcase for strong typing) I would
| never again "die on that hill" :)
|
| TL;DR: static typing: yes! strong typing: it depends.
| [deleted]
| sneed_chucker wrote:
| That's not a shortcoming of strong or static typing, that's
| just you realizing that your initial data model was flawed
| and that you either needed to unify them into a single type
| (like you did) or utilize an abstract class/interface.
|
| The good thing about stricter typing systems is that it
| forces you to handle all the cases when you're doing a
| refactor like this before it compiles.
|
| When changes to the data model happen in large codebases of
| dynamic code, it frequently gets shipped in a non complete
| state and turns into a production runtime error later down
| the line.
| Someone wrote:
| > For things like kilometers versus hours I'm still
| undecided.
|
| Those help you more if you do a lot of math involving both
| them, but that's also when it becomes a nightmare in most
| programming languages because of an explosion in the number
| of types.
|
| Let's say your code computes 3km x 4hours
|
| If so, you need a _"km hour"_ type.
|
| In many languages, you also have to write code to make that
| happen, and to make it have the same type as
| 4hours x 3km
|
| Even if you don't ever store values with those types in
| variables, you also may need types for _per km_ , _per hour_
| , _km2_ and _hour2_ for expressing the types of intermediate
| values (for example, in a physics computation, you may
| encounter _[?](3km2 /4hour2_ to compute a velocity in _km
| /hour_)
|
| And that's ignoring that you may
|
| - encounter minutes, meters, yards, etc.
|
| - want to use algorithms that compute _exp(3km)_ or
| _log(4hours)_. What types do these have? Here, you probably
| want to forget about string typing values.
| flohofwoe wrote:
| Apologies, I edited my post while you wrote your reply and
| removed the kilometers vs hours thing. But your reply makes
| perfect sense, and I think this "type explosion" is my main
| gripe with too extremist strong typing.
| asdajksah2123 wrote:
| I think the conversation becomes a lot easier once you
| recognize that there is no such thing as untyped data.
|
| There's only explicit typing and implicit typing.
|
| So the only real argument you're having with someone is when
| writing a piece of code, do they want the caller of the code or
| the input of the code's data type to be known or they want the
| data type to be a mystery to be figured out, occasionally in
| production when shit hits the fan.
| stratigos wrote:
| Unfortunately this attitude is not profitable, and also smacks
| of someone who works on their own island and costs a business
| more than they add value given their inability to work as a
| team. This attitude might find a way to be profitable when held
| by a university professor, though that does not mean its
| desirable.
| insanitybit wrote:
| This is not a "work" attitude. I would never impose my
| opinions on a team. I've worked professionally in many
| languages with a variety of type systems. In virtually all
| cases I have reviewed very positive feedback throughout my
| career, _in particular_ in terms of my ability to work well
| with others, to mentor, etc.
| waffletower wrote:
| In my country, the United States, we have broad protections for
| religious beliefs.
| scarythrowaway wrote:
| I mean, that's one reason I like dynamic typing, I get to avoid
| a bunch of psycho cargo culters for free.
|
| _cries at the thought of insanitybit not respecting me_
| optymizer wrote:
| I find it interesting that people in this thread seem to have
| absolute certainty that "types good" is true, while to me those
| two words together are largely non-sensical, just like "bytes
| good" wouldn't make much sense to debate.
| prewett wrote:
| After you repeatedly waste a bunch of time debugging things
| that static typing would have caught on the first compile,
| and you start developing a "types good" attitude. If you just
| do simple React development, you might not ever run into the
| problem. But once your programs get to a couple thousand
| lines, you start occasionally forgetting what your function
| takes and passing in the wrong things, which then get passed
| around for a while and throw an exception long after the
| problem happened. This results in very unfun print-debugging,
| particularly in a recursive descent parser or an algorithm
| that processes a lot of data.
| leptons wrote:
| >But once your programs get to a couple thousand lines, you
| start occasionally forgetting what your function takes and
| passing in the wrong things, which then get passed around
| for a while and throw an exception long after the problem
| happened.
|
| I've been writing code for 40 years, I can't estimate how
| many loc I've written, but likely over a million. One of my
| personal projects is currently over 65k loc vanilla js, and
| I never once had a problem with not knowing what type a
| function took. If you're so bad at naming things and
| knowing what a function does, I guess maybe types can help
| you. But not everyone needs it.
| optymizer wrote:
| I'll take the time to reply to both of you, because you
| seem to have opposing views.
|
| I think such a debate is largely unproductive. Like
| anything else, types have value (ha) and successfully
| capitalizing on that value depends on the context of the
| project, which includes things like developer experience,
| tooling, project complexity, requirements, deadlines etc.
|
| The only productive outcome of these debates is that each
| developer gets to slowly and frustratingly build a list
| of pros and cons as they go through the arguments
| presented by either side debating this topic. In
| addition, developers who completely disregard either the
| cons or the pros are necessarily making subjective
| decisions with incomplete data, and the project gets to
| pay the price. Just because the developer is personally
| OK with all of their projects paying that price, doesn't
| mean it's the best decision for a project.
|
| My experience has been that when starting out, projects
| get the most value out of not having types, and as they
| grow in scope and size, and the cons of not having types
| start creeping up, that's the point when gradually
| transitioning the code to being strongly typed allows the
| project to maintain its velocity _and_ quality.
| KronisLV wrote:
| > At this point it's beyond a hill I'm willing do die on. I'm
| not really interested in discussing it. If you don't get it I
| probably don't want to talk to you about it, I might even think
| less of you as a software developer.
|
| That's a pretty strong take! I don't think there are many
| things that I feel similarly about... maybe if someone
| suggested that they don't need test environments and can just
| deploy changes to prod without testing or CI/CD and just see
| what happens, when it'd be my employment on the line, but even
| that's a pretty contrived and out there example.
|
| > The amount of pre-existing respect for someone I'd need to
| have before I engage in a good-faith discussion on "are types
| good" is pretty high.
|
| My problem is that not all type systems and the way you use
| them are equal.
|
| When working with back end code, I really like .NET or even
| Java having a type system there for me. I know that people
| suggest that they have their own shortcomings (type erasure,
| NPEs, no multiple inheritance, even smaller things like C#
| enums not supporting methods) and that there are better options
| out there, but generally you can turn off the part of your
| brain that'd worry about the language too much and just deal
| with the domain problem at hand. Something like JetBrains are
| also excellent, because with the type system suddenly the tool
| also can reason about the language constructs you're using and
| give you all sorts of good suggestions and refactoring options.
|
| Whereas with something like TypeScript in combination with
| React, there are times where you fight the type system instead.
| That's just the impression that I got working on a few projects
| for a while, in comparison to React with JS (perhaps the code
| was also a bit too clever), while with Angular it felt more
| coherent to me (despite Angular being more complex otherwise
| and not really my first choice). In the end, I gravitate
| towards Vue with JS for my personal stuff, but it's not like
| you can just say no to TypeScript when you need to maintain
| something long term.
|
| I can't actually remember who said that they ditched TypeScript
| for similar reasons, but the argument was basically that a non-
| insignificant part of their codebase was there just to satisfy
| the type system. TypeScript does what it's supposed to... but
| it feels like it could be easier.
| xxs wrote:
| >maybe if someone suggested that they don't need test
| environments and can just deploy changes to prod without
| testing or CI/CD and just see what happens
|
| That's actually not hard, you need to be able to run in dry
| mode, and run the same in an existing instance (in parallel),
| then compare the results. If you are happy you can continue
| with the roll up, disabling the dry mode.
| mcv wrote:
| I'm pretty agnostic about the whole thing. The topic has been
| done to death already. Types are great, but some ways of
| handling types can get in the way sometimes, and the
| excessive type declarations in older Java was just painful.
| Dynamic types can work fine too, but they work better in
| smaller projects than in bigger ones. Types do give you a lot
| more to hold onto, even if they're only compile-time types
| like Typescript. In large, complex projects where you're
| juggling a lot of different types, you want to know what
| you've got in your hands.
|
| That's pretty much my take. I don't hate anyone for having
| different ideas about it. But if you're going to use
| Typescript, don't use 'any'. At all. Unless you really don't
| know and the next step is figuring out what type you've got.
| insanitybit wrote:
| > That's a pretty strong take!
|
| Not even one of my spicier takes, just one of the few that I
| simply don't care to engage with further.
|
| > My problem is that not all type systems and the way you use
| them are equal.
|
| We agree. Some type systems suck so badly that I can see why
| people would be tempted to believe that all type systems
| suck.
| KronisLV wrote:
| > Some type systems suck so badly that I can see why people
| would be tempted to believe that all type systems suck.
|
| But that's my point: people say that exact thing about Java
| and .NET, while I find them _usable_. Meanwhile TypeScript
| has cool stuff like union types and other stuff to the
| point where you can get pretty clever with it
| (https://codegolf.stackexchange.com/questions/237784/tips-
| for...), which many would describe as the type system being
| objectively _better_ , yet it's also more _difficult_ for
| me to use.
|
| In my mind, a good type system would let you do both basic
| stuff easily without too much work (to make sure that
| refactoring doesn't make you shoot yourself in the foot)
| and also encourage you to write the simplest code that you
| can get away with, while allowing you to get clever in the
| select few places where that is actually needed.
|
| Which is funny, because adjacent to that, Java and .NET
| (web) frameworks can be a masterclass in incidental
| complexity, even though for me the type systems don't get
| in the way too much.
|
| Edit: actually, I think I'll migrate a JS project to TS,
| this time in Vue. Perhaps Vue 3 will be a pleasant
| experience and if it won't, then I'll have a concrete list
| of things that caused me to feel this way.
| satvikpendem wrote:
| Vue is not too great with TypeScript in my experience.
| That's one of the reasons why I switched from Vue to
| React.
| mcv wrote:
| I thought Vue 3 was supposed to be native Typescript.
| nsajko wrote:
| You're confusing _static typing_ with the _existence_ of a type
| system. As an example, Julia has a rich type system, but the
| language is dynamically typed.
| patrickthebold wrote:
| I'm with you, especially in my professional life. That said, I
| think Clojure is interesting and Rich Hickey has some good
| talks in support of dynamic typing.
| TheBlight wrote:
| Not really interested in discussing it. _posted on discussion
| forum_ ;)
| auggierose wrote:
| I don't know, that is so last millennium. If you prove your
| software correct, you won't need a static type system, it just
| gets in your way. And that's a hill _I_ am willing to die on.
| WirelessGigabit wrote:
| I actually like this approach. I believe in mentoring. I
| believe in building bridges. But if we're on opposite sides of
| the Grand Canyon, it's not worth my time.
| ActorNightly wrote:
| Here is a fun fact that you don't realize.
|
| Say you can do the project in 2 ways.
|
| First way is to use a strongly typed language, think about the
| data, and design your code in the appropriate way. You code it
| up, go through the loop of compiling and fixing errors, and get
| your code to run.
|
| The second way is to write your code in Python, without
| worrying about strong types. You complete the code quite a bit
| faster, but since you also want your code to be correct, you
| spend time writing an end to end test suit for your code.
|
| The second approach is not only faster (since you are writing
| tests in both cases), its overall better. Spending time writing
| tests allows you to essentially validate things that modern
| mainstream strongly typed languages can't catch at compile time
| (for example, what happens when the input is unicode strings?).
| It also forces you to think about end to end behavior and
| making sure that is correct, rather than just the behavior
| within your code.
|
| Strong typing is a simply hand-holding tool for programmers. If
| you cannot write correct code without it, you are on a fast
| track to being replaced by AI eventually. The future of
| programming is not going to be designing data structures and
| types, its going to be using English to generate large chunks
| of code in most likely Python, and then tweak fine details in
| those.
| _dain_ wrote:
| why can't I write it in a statically-typed language and also
| write end-to-end tests?
|
| also it's pretty ridiculous to say "static type systems are
| handholding" and then say the remedy is to write your code
| with AI ..
| ActorNightly wrote:
| You can, but the reason you do this in practice is because
| the static typing languages are often not sufficient or
| strong enough. And if you are writing tests, you may as
| well do everything through testing and focus on rapid dev
| rather than worrying about types.
| gdcbe wrote:
| Call me sceptical, but I don't buy it. What makes you certain
| that's the (one) future... Also programming is a super broad
| field, and more then a field is almost more like a medium
| then a field.
|
| I honestly don't know if we'll still program by hand or not,
| but I do look skeptical at people who are very certain we
| won't. Don't think that's the first time in history people
| make that prediction...
| ActorNightly wrote:
| Compilation at its core is a translation problem. Right
| now, it would be fairly trivial to train an LLM to
| essentially be a compiler. And, you can already prompt LLMs
| on generating code for a wide array of things.
|
| As far as adoption, there is a reason why dynamic type
| languages that feature a lot more natural syntax (Node,
| Python) are used WAY more than others.
| gwervc wrote:
| Except the kind of people "saving time" writing in a dynamic
| language will skip the step of writing tests as well since it
| can be viewed as lost time.
| cjfd wrote:
| I think this is completely false. It completely breaks down
| as soon as you get into your first refactoring that is a bit
| larger than completely trivial. Typically the mess one ends
| up is one or more of the following. (1) Nothing is refactored
| because people do not dare to do it. (2) Not just some but
| most of the uncommon code paths are broken. (3) Tools that
| are used to interact with a running application are regularly
| in a broken state. You want to prevent these problems with
| 100% test coverage. As such this may be a laudable goal on
| occasion but I do notice that the code described in (2) and
| (3) are highly non-trivial to cover 100%. I also have to
| wonder what mythical developer is does not have the
| discipline to use static typing but does have the discipline
| to attain 100% code coverage. I first want to see such a
| developer before I believe in his/her existence.
| ActorNightly wrote:
| >It completely breaks down as soon as you get into your
| first refactoring that is a bit larger than completely
| trivial.
|
| This is, in fact, MUCH easier to do with a strong test
| suite that only cares about input and output rather than
| internals.
|
| The most common approach to starting a refactoring project
| is write or enhance a test suite to the point where there
| is no undefined behavior, either the program works or
| handles the appropriate errors.
|
| You don't need to aim for 100% test coverage either, you
| just need your tests to cover all possible inputs
| (including fuzzing).
| jghn wrote:
| Using your example - have a type that that enforces Unicode
| strings (or vice versa)
| mpweiher wrote:
| Well, getting this personal about a purely emotional preference
| might make people think less of a person that does that, with
| significantly better justification.
|
| To be clear: people have tried to show the long-claimed safety
| benefits for a long time, and they just refuse to appear.
| [deleted]
| halfmatthalfcat wrote:
| I've worked with my fair share of vanilla JS devs who refuse to
| acknowledge the benefit of more statically typed variants of
| the language. Most of them bemoan the upfront cost of typing
| everything without realizing the benefits of it. I absolutely
| think less of them as developers.
| leptons wrote:
| I absolutely realize the benefits of it, and I also recognize
| it doesn't cure all. Everything has trade-offs. There were
| plenty of amazingly complex and large projects written in
| vanilla JS before typescript ever existed, and somehow they
| aren't falling apart and crippled. It really depends on the
| developers involved more than the language or the dogma.
| giraffe_lady wrote:
| Not liking typescript is not the same thing as denying that
| types are valuable.
|
| TS has a very complex type system in exchange for relatively
| weak guarantees about correctness. That's a tradeoff you can
| choose to take or leave depending on the problem at hand, and
| holding that position is not the same as believing types have
| no value.
|
| Unless you're talking about elm or rescript or something then
| sure sure. But usually when people say things like this they
| mean typescript.
| smallerfish wrote:
| Typescript's typing system is great and (for me) makes
| frontend development tolerable. It's annoying that it's
| optional. tsconfig and the related ecosystem is a disaster.
|
| I still have hopes that Kotlinjs can fix the distribution
| size and the tooling around binding to js libraries.
| [deleted]
| junon wrote:
| This is pretty much my take, too. I don't hate the idea of
| TS, but TS is so painful to work with, and it's owned by a
| company I really don't like, too.
| dmix wrote:
| OP is saying it's provides weak guarantees which is a
| result of the fact they made it _easy_ to adopt and
| implement among legacy untyped code. It 's the opposite
| of painful to work with for typing systems, compared to
| something like Rust which has stronger guaruntees and
| more predictable patterns but hard requirements the full
| stack is type. The result in TS is plenty of "any"s
| everywhere and in legacy code some situations where it's
| mostly just a thing veneer of type safety.
|
| But all of that makes plenty of sense because in the
| early days it was rare to work on a real life production
| JS project that was pure TS from day one in addition to
| having TS only libraries.
|
| These days it's everywhere and the work has been done to
| move away from rampant anys in popular libraries. The
| tooling is also mature and it's rare to find major JS
| libraries not already packaged with types or a @types
| import. Turbo moving away from TS was the rare exception.
| arp242 wrote:
| > The tooling is also mature these days
|
| Well: % cat a.ts
| console.log('Hello, world!') % time tsc a.ts
| tsc a.ts 2.39s user 0.10s system 232% cpu 1.066 total
|
| More than a second to compile a "hello, world" (or 2.4s
| in CPU time) is orders of magnitudes slower than any
| other compiler or interpreter that I know of. It's a
| ridiculous start-up time.
|
| esbuild is not an alternative as it doesn't check types.
|
| What I want is "GET /foo.js" to "just" compile TS "on the
| fly" in dev; it's a simple "just works" kind of setup,
| but not possible with TS.
|
| Or for a simple system, just "roll your own":
| for f in *.ts; tsc $f >|$f:r.js watch-files
| *.js --run tsc (for f in *.ts; tsc $f) |
| minify >production.js
|
| Doesn't need to be shell, can be a simple JS script or
| whatever. You really shouldn't need millions of lines to
| call a compiler _even in simple scenarios_.
|
| What exists now is an explosion of complexity to deal
| with all this and I guess these systems are "mature",
| kind of, but for a lot of systems it's massive overkill
| (and even for larger systems it's not particularly great
| IMO). Besides, it's really a bad fix for more fundamental
| problems.
|
| Personally I wouldn't call TypeScript mature until
| compile times are roughly within the range of literally
| ever other compiler that has ever seen wide-spread
| adoption (and with that I don't mean "parallelize to 32
| cores so my threadriper over 9000 can compile things in
| 0.1s). It doesn't need to be fast: just not a huge
| outlier.
| zdragnar wrote:
| You can still use tsc for type checking via editor
| language server and quality gates (with the noEmit flag)
| and get stupid fast compilation with swc or esbuild.
|
| Explosion of complexity and "bad fix for fundamental
| problems" sounds a lot like you just have an axe to
| grind.
|
| Many other popular languages have multiple build systems
| and tools to choose from as well; it isn't a particularly
| novel challenge.
| arp242 wrote:
| _Points out real-world practical problems_
|
| _" You just have an axe to grind!"_
|
| Hmkay.
|
| I just want things to compile, with errors, like
| literally everything else works. It's really not a huge
| ask. I don't want complex bespoke setups with multiple
| compilers and background processes and whatnot. The
| classic JS/TS response is "here is the happy path with
| all this tooling, but if you want something outside of
| that then there is something wrong with you".
|
| I guess the "axe" that I'm "grinding" is that I'm having
| a lot of difficulty using TS in a way that fits with my
| sensibilities and preferences. e.g. I don't like errors
| in my editor and prefer to explicitly call the compiler
| (for any environment). I suppose I could get all of this
| to work how I want it to with wrapper scripts or whatnot:
| but it's complex, time-consuming, and isn't needed for
| anything else.
|
| Based on previous conversations about this at least one
| person will say something along the lines of "zomg what
| kind of crusty old backend unix beard doesn't use VSCode
| and want errors in their editor, you just need to get
| with the times as you're stuck in the past!!!1" but
| again: it works for literally everything else (including
| other compile-to-JS tools), and is not that "obscure" of
| a work-flow, IMHO, and we're back to a few paragraphs
| ago: "move outside the happy path and you're screwed".
| zdragnar wrote:
| I mentioned using tsc with the noEmit flag for quality
| gating, which is the same workflow you would use.
|
| `tsc --noEmit a.ts` (possibly flipping the position of
| the flag, I forget if it is sensitive).
|
| That'll check the types without spending unnecessary time
| compiling with the slower tooling.
|
| From there, esbuild or swc binaries compile the code as
| desired. They use the same tsconfig file that tsc does,
| so no need for any extra complexity. They build so fast
| that you'll not mind having a separate command, I
| promise.
|
| You could even combine the two into a simple one-liner if
| you wanted.
|
| Compared to, say, java where you have to fight over maven
| or Gradle or ant, plus endless config options in XML or
| groovy or whatever, typescript _really_ isn 't much to
| complain about.
|
| Hell, trying to set up a clojure full stack project is a
| nightmare of conflicting opinions over tooling between
| lein and shadowjs or whatever.
|
| Of the big languages, C# is about the only one with a
| "one true way", and of the smaller ones, they simply
| haven't yet developed a big enough base to grow
| contentious enough to have divergent solutions.
| dmix wrote:
| Yep almost every (serious) TS dev only uses --noEmit for
| development by default because they use VSCode/IDEs as
| their typechecking engines and then have something like
| esbuild for delivering the content to the browser
| locally. I've never had performance issues with either
| step and I use both daily.
|
| The raw output speeds aren't a very good 'practical real
| world example' as the OP described it.
|
| If anything in dev ESLint (+ Copilot) is the slow ones
| that I sometimes noticed, but there is already Rust
| driven replacements maturing in the pipeline as we speak.
| arp242 wrote:
| The performance of "tsc --noEmit a.ts" is identical, and
| it makes no difference vs. just typing "tsc a.ts", and it
| doesn't really solve "compile on demand" (with type
| checks) in any case.
|
| I looked in to this some time ago, because I couldn't
| believe it was this slow, and tsc just has a huge startup
| cost. Once it gets going it's alright (I think? Don't
| quote me) but to get started takes a long time. It's
| actually already improved because not too long ago it was
| more like 3 seconds (probably because of the
| parallelisation, which is kind of cheating IMO).
|
| I don't know about Java as I never really used it, but
| complex build systems are not unique to TS of course, but
| what they are in TS is _mandatory_ for any reasonable
| experience because it works around the fact the compiler
| is so damn slow. That 's a huge difference you can get
| started without too much effort, and you can do "smart"
| things fairly easily as I mentioned in my earlier
| comment.
|
| > they simply haven't yet developed a big enough base to
| grow contentious enough to have divergent solutions.
|
| C, C++, Go, Rust, Python, Ruby, PHP don't have a "big
| enough base"? Ehhh
|
| And my entire point is that TS LACKS "divergent
| solutions". Because it's so slow lots of solutions are
| simply not practical.
| jdeisenberg wrote:
| You might want to look into ReScript (https://rescript-
| lang.org/). It has strong static typing with type
| inference, and it is very fast.
| arp242 wrote:
| Yep, Rescript is nice, but also comparatively obscure.
| It's okay for personal projects; in company setting:
| maybe? It's certainly more complex.
| 2c2c2c wrote:
| This take is common, but personally never understood it.
| The typing is optional. Use it for the easy stuff and
| enjoy the low hanging fruit
| junon wrote:
| If the tooling is a pain to use, slow, and owned by a
| crappy corporation, and I'm not going to use the types
| anyway, then I have _even less_ of a reason to use it...
| rafaelmn wrote:
| Typescript can be very complex - it can also be incredibly
| simple - it's up to you how far you want to take it.
|
| Sure it can be an adventure to express something fully in
| it - but this is true for any type system I've seen.
|
| And I haven't seen another type system that's integrated
| into a dynamic ecosystem as well (IMO python is 5 years
| behind in terms of type checking experience) and that lets
| you chose the level of type sophistication that makes
| sense.
|
| Static typing, code analysis, automated testing, etc. are
| all great tools that become counterproductive past a
| certain point. Where that point is highly depends on what
| you're doing and typescript is one of the most flexible
| type systems at letting you make that choice. I'd say a lot
| of people are terrible at recognizing when they went too
| far with it for no practical gain.
|
| My only problem with it is that they can't fix the shit JS
| semantics.
| giraffe_lady wrote:
| I am professionally familiar with typescript and
| explicitly not making a concrete argument for or against
| it right now.
|
| I'm just pointing out that having an opinion about
| typescript is not the same thing as having an opinion
| about types. Something I think people are
| (intentionally?) conflating in these comments.
| rmilejczz wrote:
| I think it's just a path a lot of developers have
| traveled, starting with JavaScript and moving to
| TypeScript. If you've gone through that pipeline than you
| probably feel very strongly about the benefits that
| TypeScript provides and it's the fulcrum for your opinion
| on static vs dynamic typing
|
| Too many web developers, basically, I don't think the
| conflation is intentional
| PH95VuimJjqBqy wrote:
| I think you have to give typescript a bit of a pass in
| terms of types. MS had unique constraints when designing
| it originally, so it's never going to meet the
| expectations of more hardcore "typists", but I think
| they've done a great job given the unique challenges. Not
| perfect for sure, but it's one of the few newer
| technologies where I think it's a clear win.
| arp242 wrote:
| Are these people who used types but didn't like it, or people
| who never really used it and refuse to even try it?
|
| IMHO these are markedly different scenarios: the first is
| essentially just a difference of opinion, the second is a
| rather myopic attitude.
| digging wrote:
| > bemoan the upfront cost
|
| This applies to much more than static typing as well.
| Anything built, can be built well or it can be built quickly.
|
| Although I often have to make trade-offs for immediate gain
| at work, there is a big difference between the quality of my
| work over time vs the quality of other devs who default to
| immediate returns. I will say in their defense, they play a
| role in the team. But I wouldn't want to work on a team where
| avoiding upfront costs was the expectation rather than the
| exception.
| lo_zamoyski wrote:
| Have they considered languages with type inference?
| waffletower wrote:
| And I definitely think less of you as you as a developer as
| you openly admit to dogmatic and myopic prejudice regarding
| the nuances of typing systems and the complexity of software
| development contexts.
| lijok wrote:
| Interesting. Would you have had the same response if GP
| stated:
|
| "I've worked with my fair share of vanilla JS devs who
| refuse to acknowledge the benefit of testing. Most of them
| bemoan the upfront cost of testing everything without
| realizing the benefits of it. I absolutely think less of
| them as developers."
| waffletower wrote:
| Again another binary dichotomy that doesn't neatly fit
| reality. I imagine the number of developers that would
| unilaterally dismiss all testing practices is very small.
| halfmatthalfcat wrote:
| I mean, I'm not going to say it to someone's face but I'll
| definitely be judging them. Most of those who have pushed
| back against typescript have done so for similarly dogmatic
| reasons or even straight ignorance (I dont want to learn
| something new), so I'm not sure who is really the winner or
| loser in this situation.
| manicennui wrote:
| The problems with JS go far beyond its dynamic typing.
| ecshafer wrote:
| This sounds like its just Typescript evangelizing. But while
| I love types, Typescript kind of sucks and sucks the fun out
| of writing Javascript. If I am going to add a compilation
| step to get types, I would rather write Scala or F# and
| compile to JS, then you also get rid of all of the warts of
| JS that Typescript _doesn 't_ get rid of.
| IshKebab wrote:
| I agree Typescript doesn't solve all the warts. But it does
| solve a lot.
|
| The really issue with compile-to-Javascript languages is
| debugging. Have fun stepping through your incomprehensible
| generated code in dev tools.
|
| (Except Dart which has really good Dev tools support; I
| guess they can poke the right people to make it work.)
| JonChesterfield wrote:
| It _really_ matters which static type system is in question.
|
| SML or Haskell? Yep, like those ones. The languages would not
| be so useful without their compile time type checking.
|
| C? Not worth the trouble. C++? Not worth the tarpit or the
| trouble.
|
| Python? Definitely not keen, that language was much better
| without the annotations.
|
| Typescript people really like but I haven't played with. I'm
| pleasantly surprised that unsound static + sound dynamic works
| well.
|
| Type annotations are not inherently good. Some type systems add
| a lot of value, some really don't.
| oldpersonintx wrote:
| [dead]
| chongli wrote:
| This is not about type annotations, it's about type systems.
| You can write Haskell programs without any type annotations.
| Your program will type check and compile just fine. The value
| comes from the checks (as well as the inference,
| documentation, optimization, and everything else a modern
| type system gives you), which you don't have to write
| yourself, you get them for free.
|
| People who say they prefer dynamic languages are really just
| saying 'no' to all these free benefits.
| JonChesterfield wrote:
| If your language is wholly type inferred, and the type
| system is expressive enough to deal with whatever one
| wishes to write, it is indeed "free". If you ignore compile
| time performance, run time performance, and that you're
| writing in something between Idris and vapourware.
|
| Otherwise the cost is merely being unable to write anything
| that the type checker does not understand, and however long
| your compiler takes to do the checks on what it does
| understand.
|
| Also a fair chance the whole program must type check before
| you can see the results of changing a subset. In the worst
| case you get to hunt down all the unused variables before
| it'll run the test suite.
|
| I prefer dynamic languages. That makes me a heathen on
| these boards, to be ignored or chastised for my stupidity.
| Regardless, those benefits do not come for free.
| WJW wrote:
| Even though I usually fall more on the "types good" side of
| the discussion, the advantages you listed are not free at
| all. They come at the cost of at least:
|
| - having a compile step in between writing and running your
| code. This drastically slows down the feedback loop of
| development. The more your compiler has to check for you,
| the slower it gets.
|
| - being able to run your program in a half-broken state.
| This may not seem like much of an advantage, but sometimes
| it is good to just be able to run a broken piece of code to
| see _how_ it crashes. This is especially important when
| learning to program, but is still very beneficial when
| learning a new language or framework, or sometimes for
| debugging.
|
| - As someone who has contributed to the main Haskell
| compiler, I can definitely confirm that a more complicated
| type system can slow down development of the language
| itself too. It takes significantly more effort to grok all
| the possible interactions as the codebase of the compiler
| grows.
|
| Don't get me wrong, I think encoding and enforcing program
| properties with types is a great idea that will grow
| further in the future. But the dynamic languages gained
| popularity for good reasons, and some of those reasons are
| still valid today.
| ActorNightly wrote:
| >SML or Haskell? Yep, like those ones
|
| Not strong enough.
|
| If you are proponent of strong typing, you need something
| that is effectively a theorem prover. I.e when you define a
| type, you define the scope of the data it can hold,
| operations on that data, and the resultant types of those
| operations. That way, when you code compiles, it is by
| definition "correct".
|
| When you accept anything less then that, you are basically
| making a statement that you are willing to forgo some of that
| correctness for convenience, which is fine, but that means
| that no language out there is really good or bad.
| DonaldPShimoda wrote:
| Theorem provers' type systems are not necessarily
| _stronger_ than SML 's or Haskell's; they are _more
| expressive_ , which is a separate thing entirely.
|
| That said, your position is also just weird to me. Yes,
| theorem provers have nice type systems that are wonderfully
| expressive. The trade-off is that some _common_ programming
| patterns become difficult to use or are even impossible.
|
| When it comes to everyday programming, I don't think
| theorem provers are at a point where they are particularly
| useful. Not everything needs to be proved formally, and I
| don't think this position is at odds with the belief that
| static type systems are generally "better" than dynamic
| ones.
| ActorNightly wrote:
| > The trade-off is that some common programming patterns
| become difficult to use or are even impossible.
|
| Not really. Strong and expressive typing at its core is
| simply creating data packaging containers that have
| defined operations on them. It says nothing about logic.
| You may be referring to the functional programming aspect
| that comes with strong typed languages, which is related
| but not the same as strong typing.
|
| The point is that typing is just a tool that a programer
| can use, whether its built into the language or ran
| statically like MyPy. You can take a piece of code in C,
| and write a test suite on input and output of that piece
| of code, and accomplish much of the same thing that
| typing accomplishes. However, in the case of
| strict+explicit typing, the idea is that you wouldn't
| need tests in the first place, because your code would be
| correct by nature of compilation.
| DonaldPShimoda wrote:
| No, you are wrong.
|
| Some theorem provers, such as Coq, are not Turing-
| complete. This means you cannot write some programs, and
| in particular you cannot write infinite loops in Coq.
| Infinite loops are a common pattern (e.g., a REPL or a
| GUI display waiting for input).
|
| This is a trade-off, as I said. You gain the expressive
| type system, but lose the ability to implement certain
| programming patterns. It has nothing to do with the
| strength of the type system.
|
| ---
|
| > whether its built into the language or ran statically
| like MyPy.
|
| All (true) type-checking is static, so MyPy "running
| statically" is not a noteworthy feature to distinguish it
| from other type checkers. I guess this point may seem
| trivial to some, but the broader context of this
| conversation involves conflation of the terms "static
| type system" and "strong type system", so your misuse of
| the word "statically" here seems worth pointing out.
|
| That said, whether you use an external tool to check your
| types or the type-checker is built into the compiler is
| irrelevant, and I'm not sure why you brought it up at
| all.
|
| ---
|
| > You can take a piece of code in C, and write a test
| suite on input and output of that piece of code, and
| accomplish much of the same thing that typing
| accomplishes.
|
| Depending on the perspective, this is factually
| incorrect.
|
| Type-checking is an ahead-of-time operation that
| guarantees the absence of certain classes of errors at
| run-time. Writing tests to check for the absence of such
| errors is not equivalent, because you have not _proved_
| anything; you merely gain confidence. They are
| semantically distinct, even if you write many tests to
| gain a lot of confidence.
| ActorNightly wrote:
| >Some theorem provers, such as Coq, are not Turing-
| complete. This means you cannot write some programs, and
| in particular you cannot write infinite loops in Coq.
|
| You are talking about languages, Im talking about the
| concept. The modern theorem provers aren't up to the
| task. Due to Rices theorem, you cannot "fully prove" a
| program, so a language that does this couldn't even
| exist. The strict typing however can be applied to
| subsets of the programming space, namely the data
| processing pipeline, whereas higher level stuff like the
| actual server code that does have an infinite loop to
| listen to requests can be written in whatever.
|
| The point is that no language recommended for strong type
| safety today is anywhere fully complete to include the
| rigor of something like a theorem prover, and anything
| less then that is basically your own opinion on what is
| "good enough".
|
| >Type-checking is an ahead-of-time operation that
| guarantees the absence of certain classes of errors at
| run-time.
|
| Run time errors are no different than compile time errors
| as far as testing is concerned. Its not like the computer
| blows up when you have a seg fault. And you absolutely
| can prove what you need for operation.
|
| Say your input to your code is an HTTP request of length
| x. And output is some data processing on that request.
| You can write a test suite that is basically like this
|
| 1. Ensure that code returns a well defined error for x
| values outside of given range.
|
| 2. For all valid ranges in x, test all possible values of
| every byte in that range, and ensure correct behaviour.
|
| While overkill, this will absolutely exercise every
| single piece of your code and prove correctness. You can
| also couple this with checking things like memory access
| JonChesterfield wrote:
| SML is good enough for theorem proving. That's what it was
| written for. Though you probably want convenience libraries
| on top, maybe the one called HOL.
| yxhuvud wrote:
| 100% this. Developer experience in a language is a so much
| bigger question than if it has static types or not.
| xigoi wrote:
| > C? Not worth the trouble. C++? Not worth the tarpit or the
| trouble.
|
| The OP said _strong_ static type system, so C and C++ are out
| of the question.
| oldpersonintx wrote:
| [dead]
| RHSeeger wrote:
| Sometimes the question isn't "are types good", it's "are the
| costs associated with static types worth it for this particular
| use case". And the answer is almost always yes; but the
| "almost" there is important.
| msla wrote:
| Similarly, choosing between 'int' and 'long' isn't part of a
| type system, unless the only semantics your data has is being
| an integer of a given width. Types are semantic, and telling me
| "height is 32 bits" tells me jack shit about units of measure
| or anything else.
| sbjs wrote:
| Yeah I've been in that camp since like 2016. TypeScript is
| basically an essential for me now, and I don't debate it with
| anyone. If they don't get it, it just gives me a baseline
| understanding of how little experience they have in real world
| software development.
| leptons wrote:
| Trigger warning: I love to write assembly language.
|
| I probably love assembly language more than C#, or C++, or any
| of the strongly typed languages I use.
|
| Assembly language has no types. It doesn't pretend types even
| exist.
|
| Are you going to look down on me because I like to write
| assembly language?
| oweiler wrote:
| God, what has become of healthy discussions? People getting
| more and more toxic these days...
| insanitybit wrote:
| I'm all for healthy discussions, but I think it's fair to say
| "I've had this discussion enough times, unless you're really
| bringing something new to the table, I'm opting out".
| digging wrote:
| Is it really a healthy discussion? At least with respect to
| JS vs TS (which is the most common argument as it's a choice
| every front end team has to make), it's blogs saying "fuck
| types, I like JS only." I'm not going to step in and tell
| another team what to use but whining about the difficulty of
| static typing is just not a productive conversation. I've
| been converted by the top level comment; I'm not longer
| interested in entertaining the discussion.
| sproketboy wrote:
| [dead]
| booleandilemma wrote:
| I don't think the opinion is even controversial at this point.
| Even the hardcore JS developers I know have come around to using
| TypeScript.
|
| If you can't at least admit to the benefits of static types in
| 2023 then you probably don't have experience building or
| maintaining large software systems or working with a team of 15+
| people, many of whom you've only met over Slack.
| hangonhn wrote:
| Does anyone here know how Standard ML inferred types? I really
| loved coding in SML and its strongly type checking system. The
| amount of bugs I produced was noticeably less. What I'm wondering
| is why we can't use a similar system as SML to infer the types.
| Other languages haven't adopted a similar system so there must be
| some kind of trade off. What was the downside?
| valcron1000 wrote:
| Look up 'Hindley-Milner type system'. AFAIK, one feature that
| break this system is subtyping which is very common in many
| programming languages.
| nyssos wrote:
| > Does anyone here know how Standard ML inferred types?
|
| SML uses Hindley-Milner (with some modifications to support
| imperative code). Many statically typed functional languages
| descend from it: Haskell and OCaml are the most prominent.
|
| > Other languages haven't adopted a similar system so there
| must be some kind of trade off. What was the downside?
|
| If you're asking why existing popular languages don't adopt it:
| they can't. HM type inference requires a HM type system, and
| they've committed to a different one. At best you could get
| good inference on a HM-typed fragment within the language
| (though even that would mean making a lot of painful tradeoffs)
| but it would break down the moment it made contact with
| existing code.
|
| If you're asking why HM languages didn't become more popular?
| Historical accident, in my opinion. I don't think it has much
| to do with the type system, given how fundamentally awful
| Java's is.
| mrkeen wrote:
| > What I'm wondering is why we can't use a similar system as
| SML to infer the types.
|
| We can and do! Use SML!
|
| People just don't find out about the good type systems because
| the market is crowded out by mainstream shit.
|
| And people write pieces about how good this shit is: "I was
| going to add an Int to a String but the compiler stopped me!
| Less [sic] bugs!". With arguments like that, why would you
| switch camps?
|
| Or sometimes you get fed shit and get told it's inference: "I
| can replace the first word on the line with 'var'!".
|
| So what are the downsides?
|
| Inference doesn't play well with inheritance or mutability.
|
| If you read Effective Java and see the points about avoiding
| mutation and inheritance, then these downsides may very well
| seem like upsides to you.
|
| Why did you stop coding in SML?
| hangonhn wrote:
| SML has never been used in any of the jobs I've had. I
| definitely have a very functional programming bend to my
| preferences. The closest I've come to doing something like
| SML for work is to use Clojure.
| yc-kraln wrote:
| The example from the article without any explicit arguments
| reminds me very much of objective c's message passing concept,
| which I actually quite liked and used very much. So, I guess the
| answer is: there is no objectively correct way to do things,
| except if the thing you are trying to do is get "engagement" then
| take an extremely strong stance on something which has no
| objectively correct answer.
| alexvitkov wrote:
| You're not "moving faster" if a typo is a runtime error and
| you're not "more productive" if you can't change a function
| signature without having to grep your codebase to find all
| callsites and pray you fixed them all.
|
| Types are good, but as with anything else people take it too far.
| Making it your life goal to encode all business logic in the type
| system results in an even more incomprehensible mess than not
| having types at all. If the type name can't fit on one line in
| the error message, you've gone too far.
| ranting-moth wrote:
| I've seen some insane Typescript type definitions. To be fair,
| they were defined to work with historic vanilla JS code where
| so many things could have been stuffed in the poor variable.
|
| I'm forever grateful for Typescript, but I wouldn't be
| surprised to see some of that code in a future research paper
| titled "The era when types went too far".
| alexvitkov wrote:
| I'm mostly fine with bad TS definitions since the types are
| cosmetic and you can always 'as unknown as whatever' your way
| out of an insane type definition. If someone nests 5 generics
| in Rust/C++ you'll have a much worse time.
| sonusario wrote:
| Do you still find this true when taking type aliases into
| account?
| globular-toast wrote:
| The first time I saw this pattern play out was with CSS vs
| table layouts.
|
| A lot of web devs these days don't remember a time before CSS
| but, back then, we used to use tables for page layout. This
| was really an abuse of the `table` element of HTML, which was
| designed to display tabular data, but it was basically the
| only way to achieve many layouts like having a side menu bar,
| for example.
|
| Abusing `table` was bad for many reasons, including
| accessibility. People started to care about the semantic web
| and remembered that HTML is a markup language for content,
| not a style language for layout. So people advocated for
| using CSS for layout and reserving `table` for actual table
| data.
|
| But gradually this rule became both simpler and more
| ridiculously followed. People started talking about "using
| divs instead of table". They would look at a page source and
| if they saw `div` it would get a nod, but if they saw `table`
| the developer would be relentlessly abused because `table` is
| old-fashioned. Eventually, of course, someone reinvented
| tables using divs and CSS.
|
| And then people realised the pendulum had swung too far.
| timsneath wrote:
| There's an irony that this comment is posted on HackerNews,
| where the entire page of comments is hosted in a big
| <table> for layout. Not sure if this is good or bad!
| BLanen wrote:
| Bad, tables are bad for tree-based data.
| david422 wrote:
| > I've seen some insane Typescript type definitions.
|
| That's just because the code is bad, not because the type is
| bad.
|
| That's literally just the definition of, this code is so bad,
| let's just not type it.
| digging wrote:
| Agreed. I've left a few `any`s or `as unknown as X` in
| place before and typically leave a comment alongside it.
| Something to the effect of: "This code is bad and will take
| too long to refactor. Every time you trace a bug back to
| this code, please adjust the logic and typing a little bit
| to prevent the kind of bug you encountered. Eventually we
| can replace this bad code with good code."
| vonwoodson wrote:
| You know, I'd always been like "`from pdb import set_trace:
| set_trace()` and you can interactively edit. I don't care what
| the type is because I can interact with my running program
| better than a compiler" (followed by intense nerd chortling).
|
| You know, until the program is non-trivial: passing data
| between systems on a queue; using async, threading, and/or
| multiprocessing; compiled binary critical-performance
| libraries... and I'm left wishing I'd written the whole thing
| in Erlang.
| duped wrote:
| > if you can't change a function signature without having to
| grep your codebase to find all callsites
|
| Every time I see a developer make this complaint about static
| typing I wonder what the hell they're doing with their type
| definitions and architecture where this is actually a problem.
|
| > and pray you fixed them all.
|
| If this isn't detected for you at compile/build time you're not
| using static typing
| _dain_ wrote:
| The comment you're replying to is criticizing dynamic typing
| here, not static typing.
| Double_a_92 wrote:
| > you can't change a function signature without having to grep
| your codebase to find all callsited and pray you fixed them
| all.
|
| I really wonder how people can actually work like that. Is
| there some overarching methodology like super strict tests with
| 100% code coverage or so?
| emerongi wrote:
| Tools like https://comby.dev/ help with the refactoring
| itself, but I'm never really 100% confident.
| JonChesterfield wrote:
| Regex find and replace across a codebase works fine,
| especially if the functions aren't overload sets.
| thfuran wrote:
| If you have a tiny codebase maybe, but if there are a
| couple million lines, it's likely that a pretty significant
| number of functions are sharing names.
| JonChesterfield wrote:
| Those would be the overload sets
| globular-toast wrote:
| > You're not "moving faster" if a typo is a runtime error and
| you're not "more productive" if you can't change a function
| signature without having to grep your codebase to find all
| callsites and pray you fixed them all.
|
| I don't see how either of these things relate to type
| discussions. A typo can certainly lead to incorrect code in the
| most strongly typed, staticest language there is (otherwise,
| what the hell is writing code even for?) What's worse: a
| runtime error or no error that produces the wrong result?
| Running a Python project might be quicker than compiling a C++
| project. Dynamically typed languages can do better than
| grepping for function calls.
| tabtab wrote:
| Although a lot depends on personal preference, in general "root"
| infrastructure is best on strong typing, while "glue-ish" scripts
| best as dynamic.
| [deleted]
| jillesvangurp wrote:
| This debate is a lot older than typescript vs. javascript and
| dates back to at least the nineties when languages such as
| python, perl, and others were creeping into production systems.
| Before that there were already things like tcl/tk and a few other
| things of course. And of course people were messing around with
| things like Basic as well.
|
| A lot of the arguments against typing are a bit stale.
|
| - We have transpilers now. Even most javascript coders use a
| transpiler or at least a minifier. The overhead of a type checker
| in such a tool chain is pretty minimal. Especially on a modern
| laptop.
|
| - We have type inference and a few other modern compiler features
| now. Typing is a lot less verbose in e.g. Kotlin than it is in
| Java. Java now has a little bit of type inference but it is still
| pretty verbose in comparison. A lot of the typing is just added
| by tools as well.
|
| - A lot of languages like python, ruby, and others have types
| now. And spin off languages that have better typing (e.g. Mojo,
| Crystal) and preserve most of the original languages perceived
| elegance. Just goes to show that typing can be done without too
| much compromises.
| todd8 wrote:
| I understand that modern type systems can do anything (that can
| be computed) since they are Turing complete. So are Java generics
| and C++ templates and Lisp's macro systems, but I don't want
| these things.
|
| I've written a number of Turing machine programs; yeah it's
| impressive that an imaginary machine that is so simple can run
| any program that runs on any other computer, but it's no fun
| writing code for a Turing machine. For the Theory of Computing
| studying Turing machines is important.
|
| If I don't want Turing complete type systems, what do I want?
| Well, first off, the bugs I find in my programs that are more
| troubling don't seem to be stopped by strong type systems. What I
| want is to be able to declare assertions in my code. For example,
| I'd like to tell the compiler that the variable _year_ must
| always satisfy (2000 < _year_ < 3000) and that in a certain
| block of code that _x_ and _y_ are always within 0.5 of each
| other. I want the compiler to ensure that these invariants are
| satisfied by a combination of compile time and run time checks
| generated by the compiler.
|
| The problem is that we can't expect programmers to use Turing
| machine like type declarations, because the programmer must now
| program the type system without bugs to ensure that the types in
| the program carry enough information that higher level assertions
| can be made about the original program's correctness.
|
| TLDR, I want to work with higher level assertions about the code
| than that provided by complex types.
| kazinator wrote:
| [delayed]
| ranger207 wrote:
| Dynamic typing is fine for exploring. If I'm trying out a new API
| and don't want to look at the documentation every 30 seconds (or
| more realistically the documentation is terrible) then writing a
| simple service in Python is a great way to gain experience.
| Someone mentioned Julia; I think that most of the stuff you're
| going to be doing with Julia is exploring so it's fine that it's
| dynamic. But, for anything actually intended to be used, all the
| advantages of strong static typing come into play. The problem
| arises when people start out exploring a problem with a dynamic
| language, get something working, and then try to expand that
| dynamic program into something production-ready.
| Chabsff wrote:
| While I agree with most of the post, it's just the tip of the
| iceberg of the discussion. Stuff like interfaces, traits,
| generics, concepts, inference, duck-typing, implicit conversions,
| etc. all fuzzyfy the notion of "Strong Typing" in various ways,
| some more than others.
|
| The real discussion is not about types vs no-types, it's about
| the role and place for each of these bending of the rule and
| their associated tradeoff in different contexts. Op even takes
| inference for granted towards the end of the post, but make no
| mistake, that's a form of weak(er) typing.
|
| For example, writing template code in C++ without frequent use of
| type inference (aka. auto) can be an absolute nightmare (I
| suspect that extends to generics programming at large, but C++ is
| where I have the most experience here), and the legibility gains
| from making use of it for iterators is broadly acknowledged as
| being easily worth the obfuscation for scope-limited variables.
| But there's also a strong case being made to avoid its use
| entirely in most other contexts.
| kagakuninja wrote:
| C++ templates are a nightmare, because it is also a compile-
| time macro system. The cryptic, giant error messages from
| forgetting a > were legendary. Maybe this has improved, I
| haven't used C++ in a long time.
|
| Java by contrast has a greatly simplified generic system; Scala
| improves on that with robust type inference, making generics
| pretty trivial to write and use.
| Chabsff wrote:
| 100% agreed on all points. But even in these languages,
| writing generics remains greatly facilitated by the use of
| type inference, which is all I'm saying.
| cmrdporcupine wrote:
| It's interesting we've gotten to this place where the discussion
| happens like it is on this forum, where acceptance of strong
| static typing is pretty high.
|
| 10 years ago the bias was strongly the other way. And in many
| shops I've worked in, there was an _intense_ hatred of having to
| declare types.
|
| I like to think it's the development of better/smarter type
| systems in mainstream programming languages (vs say Java which is
| what was dominant then), as well as maybe maturing of software
| engineer practices.
|
| But I also fear it's just the trend-pendulum ticking.
|
| That and I notice a _lot_ of Python jobs out there, which is an
| ecosystem I 've kept away from for the last 10 years precisely
| because my professional experiences with large dynamic-typed
| late-bound Python codebases was terrifying. Beyond NumPy & ML
| related projects, I fear that this might be indicative that the
| _" types are just getting in my way"_ crowd is still very
| influential...
|
| Finally I also think it's important to distinguish two concept
| that get mixed up -- type vs binding: static typing vs dynamic
| typing and early-binding vs late-binding. It so happens that most
| languages that emphasize static typing emphasize early-binding,
| and vice-versa; but it's entirely possible to have very strong
| types but still introduce sloppy late binding decision behaviour
| that ends in all sorts of runtime exceptions. Java is/was
| notorious for this. Reading configuration files to drive
| application behaviour, or doing things like the Rust Axum
| framework's "axum::extract::State" stuff, which can blow up at
| runtime; they're not strictly type issues, but get mixed up in
| some of the things people are talking about here.
| syndicatedjelly wrote:
| What were the arguments back then that supported the opposite
| bias?
| cmrdporcupine wrote:
| "Move-fast & break things." "Test-first-design & aggressive
| unit testing is the solution."
|
| To be charitable, perhaps that the type system was getting in
| the way, physically of what they wanted to accomplish
| conceptually.
|
| I actually think it has more to do with object-oriented
| programming as it was propagated through C++ and Java. We
| were told (and believed) that OO abstractions would solve
| many software complexity problems. The focus of a lot of
| programming work was/is on bringing these OO design patterns
| into play. In large part the OO thing is about a kind of
| dynamic dispatch. And yet languages like Java imposed a very
| rigid way of doing OO, and made some of the patterns awkward
| to express.
|
| So if you believe in your heart in the promise of OO, but
| find that your OO experience is relatively handicapped by
| your static type system, one then blames the type system.
| Ruby was maybe the best example of where this line of thought
| was going/coming-from?
|
| I think we are getting past this by getting (somewhat) past
| OO as a dominant design methodology. But also by adopting
| languages with richer static type systems.
| karmakaze wrote:
| I'm also on the side of static typing being beneficial. I would
| always however consider the case at hand individually rather than
| reject it offhand because it lacks it. e.g. a complex distributed
| working system written with say Elixir or Erlang isn't easily
| replaced with typescript. Not all systems are better with any
| static typed language than any without.
|
| Once you reach a certain size of developers, add static typing if
| available, e.g. TypeScript, Sorbet, etc
| vouwfietsman wrote:
| Couldn't agree more. I suspect in the future software
| professionals will be apalled by the abuse of freedom that we
| currently have in languages.
|
| The more freedom we take away, the higher quality software we
| produce. Looking at you, Rust.
| goalieca wrote:
| This is an old thought but one which favours declarative
| languages over procedural ones.
| vouwfietsman wrote:
| No it's not, I had it just now.
| [deleted]
| wait_a_minute wrote:
| > The more freedom we take away, the higher quality software we
| produce.
|
| How are you measuring this?
| vouwfietsman wrote:
| Every fortnight during a full moon.
|
| All kidding aside, obviously I don't. That shouldn't detract
| from my statement at all though, nobody measures anything
| about software. We're all in the dark. Thats actually
| reinforcing my beliefs: we are in the dark because software
| is unmeasurable _because_ of the freedoms taken by
| programmers that fail to abstract or fail to be formalized.
|
| Formalizing software, and then starting to measure changes
| rigourously, is the first step we have to take towards
| becoming a mature industry.
|
| Formalization is the oposite of freedom. People think
| software is like art, where freedom of expression broadens
| horizons. This is no longer true, most software is not art,
| most software is buttons that make money when clicked.
| marcosdumay wrote:
| > People think software is like art, where freedom of
| expression broadens horizons
|
| Artists live by constraints. Nobody prefer a blank canvas.
| xigoi wrote:
| > Nobody prefer a blank canvas.
|
| Abstract art enjoyes would like to have a word with you.
| esafak wrote:
| Joke's on them; that's not art :)
|
| What's next, sit silently behind the piano for four and a
| half minutes and call it a musical performance??
| xigoi wrote:
| > Nobody prefer a blank canvas.
|
| Abstract art enjoyers would like to have a word with you.
| okeuro49 wrote:
| I agree, and I think the industry does too. Types are being
| retrofitted onto languages, like PHP, or added as a superset of
| the language, like with Typescript.
| thot_experiment wrote:
| It seems like such a weird thing to have a super strong opinion
| on. Sure if you only ever do one specific thing maybe there's an
| argument to be made that one is better than the other. I think
| there are just some problems that are best solved with statically
| typed langs, and some are better solved with dynamically typed
| langs. IIRC research shows it's a wash.
___________________________________________________________________
(page generated 2023-10-04 23:02 UTC)