Language Pragmatics Engineering
borretti.me
borretti.me
You observe this with types. Dynamic types feel faster, at the REPL, when you’re coding at 1Hz, because you’re not factoring in the (unseen) cost of future bugs, the cost of refactors you won’t do because you don’t have the confidence to refactor which static types give you, the cost of legacy software that can’t be replaced because it can’t be understood by anyone, the cost of a Python server doing four requests per second while you pay five figures to AWS every month.Of course, that 'a g i l i t y' of dynamic typing is impossible to give up. The devs must churn out code ASAP, maintenance be damned -- mostly because they probably won't be maintaining it.
- Average tenure in a dev job being so short means it is detrimental to optimize for the long term.
- Promotion policies in most companies are heavily balanced towards "shipping more" rather than towards "shipping better". Even in companies without formal policies around this, "more" is way more visible than "better". Even more so if you get to be the hero firefighter who rescues the site from downtime, nevermind that it was your code that set the place on fire in the first place.
- Software as an industry has very low capital requirements, which makes it easy to get into. However, that also means competitors can spring up very quickly and many companies respond by constantly churning out features to stay ahead of the competition.
- It is IMO way easier to teach yourself programming with a dynamic language rather than with a statically typed one. Interpreters are certainly not exclusive to dynamically typed languages, but they are definitely more prevalent. With so many devs being autodidacts, it's not a surprise that many of them default to dynamic languages.
Don't you mean, constraints are found when the program throws an unexpected exception and leaves you with a largely meaningless stack dump :)
I'd rather have the system tell me "you can't do that" much earlier - at compile time, not run time.
I use python quite a bit, but hate the thought of all those never-exercised control paths, which only occur in the most unusual circumstances - and I know silly problems will show up when those paths do get executed :(
I'd love to see some examples of this. Links?
In "some cases" doesn't mean the statement is bs. Generally jit is slower than compiled code. There are exceptions to every rule, we use generalizations to reason about the world anyway.
In other words, if static types alone are giving confidence to refactor, it is a false confidence except in the most trivial of cases.
As a consequence, a lot of peoples primary experience with type systems is limited to "this should return a list of strings", which like you said, is one small class of problems (though I'd argue it's huge win compared to not having that guarantee).
Every project needs tests, but like all things, what happens in practice is seldom ideal and thus the more you can offset to (reliable) automated tools the better.
Simple, vanilla Haskell is approximated more and more by the mainstream languages: Optional types, andThen().orElse() and friends and other things - which I am really happy about!
Why not use a more mainstream langauge then? For me, there are at least 3 hard reasons:
1) The stuff mentioned above is old, battle-tested and deeply embedded into the language and the community - it feels ergonomic to use.
2) IO-being-a-library is a paradigm that produces programs that I love to maintain, also when others written them.
3) Haskell has nice interfaces that I miss in mainstream languages, Functor and Monad for example. My prediction is that in around 5 years, mainstream languages will start to offer these kind of interfaces - starting from "Wait, what else can we do with andThen() and optional chaining and so on?"
Making it hard to YOLO your I/O does not seem to be paying off very well for Haskell; the cost in adoption often outweighs the gain in safety. Yes, Django codebases occasionally have bugs due to I/O happening at the wrong time, but that's pretty far down the list of causes of bugs in Django codebases.
Likewise the argument against macros seems to be driven by nothing more than personal taste. (And again, I dislike macros! But you have to actually make the argument why they're bad. Certainly my experience is that checking generated code into source control is worse, not better)
salience bias: measuring what is seen and not what is unseen.
And he did not say all macros are bad, giving the example of Common Lisp macros being good. Why? Because you can easily expand them (the language itself gives you the capability, not just an IDE... but of course with SLIME it's one shortcut away) and see the actual code you will get running.That seems pretty unconvincing. If it's important for macros, why isn't it important for regular code? And yet taking a Haskell function and dropping down to the corresponding Core is no easier than expanding a Rust or OCaml macro.
The OP might have been bitten by bad macros and bad code generation (early and repeatedly).
> Moving with the arrow keys, erasing text by holding backspace for an eternity feels slow, but it is predictable and reliable. Vim or Emacs-style editing, where you fly through the buffer with keybindings, feels faster, but a single wrong keypress puts your editor in some unpredictable state it can be hard to recover from.
I've been using neovim for about a year now. I don't think I've ever entered a state from a mis-click that is hard to recover from yet. The worst case scenarios tend to result in something taking comparable time to if a mouse was used.
It seems to me that the fundamental definition of a function/method should be a compile time executed function that generates a syntax tree always (assuming the compiler dog-foods itself or can parse and interpret it). Much like Python has metaclasses or Rust's procedural macros but it's just assumed by default.
It's kind of unfortunate that a language with managed effects & capabilities hasn't gone mainstream. Maybe it doesn't have the right ergonomics yet.