Does anyone have a strong argument for people that...
# thinking-together
s
Does anyone have a strong argument for people that insist dynamic types are better or easier for novice programmers or non-programmers than explicit types?
j
I'm generally an advocate for static types but I think it's hard to argue against the notion that it's easier to learn a dynamically typed system. Obviously there are less rules and less syntax (or interactions etc. if we're not using syntax) in a dynamically typed system. ML-family languages actually require you to learn a kind of logic programming to understand type inference, on top of applicative-style programming to understand terms. Type errors are more abstract than runtime errors and require more cognitive effort to understand. I sometimes wonder if a type system could be built that reported errors at particular values. I think this would help beginners a lot. "If you call
f('hello', 5)
then you will end up calling 'hello'+1 here" is a lot more friendly than "cannot unify constraint
x : number
arising from use of
+ : number -> number -> number
with
x : string
in type signature of `f`"
i
I don't... but I'll die on the hill that dynamic languages are better for expert programmers. * ducks *
❤️ 1
y
https://www.reddit.com/r/ProgrammingLanguages/comments/c1899u/steady_typing/ Lamdu’s new video discusses exactly this. It doesn’t necessarily say that static types are better, but it overviews the pros and cons of dynamic vs explicit static types vs inferred static types vs our own approach “Steady Typing” which we believe can make static types better 🙂
🍰 2
❤️ 1
s
Basic, Python, VB, Excel, Racket... It certainly seems that programming languages and environments designed for - and popular among - novice and non-programmer computer users are dynamically typed.
w
I'm a static typing fan, but I generally would agree that dynamic typing is easier to get started with. A few reasons I can think of: 1) dynamic types "just work", i.e these languages tend to be forgiving that if you pass somewhat mismatched types (e.g. an int where a string is needed) it still does something sensible. In a sense, things are not always either typed correctly or incorrectly, there's a large space of situations in between that in static languages is an error and in dynamic ones it is benign. 2) You typically have less types to deal with, and they are more powerful, like dynamicly typed dictionaries are a swiss army knife of data structures. 3) Just purely the syntax of static typing is confusing to deal with, especially once you factor in genericity.. though some static languages like Lobster solve this issue 🙂 4) get results quicker means more motivation in learning
🍰 1
❤️ 2
in general: less primitives to learn
👍 1
s
so my thoughts are explicit types are better because I'm working on a visual programming language. Users explicitly picking type gives them the "best" (given constraints of the UI system and production realities) UI to edit that type, rather than a text box. It might be ok to make a variable dynamically typed and keep types only in constants, I'd have to come up with some interesting type conversion rules though
y
@Scott Anderson my table includes this as the “Type assisted editing” row where indeed static typing wins
👍 1
d
My language, Curv, is dynamically typed, because that makes the language simpler and more powerful. As Wouter has said. The next version of Curv supports visual programming. I want to find a way to support context sensitive editing without losing the simplicity and power of dynamic typing. I don't need or want the ability to prove that an entire program is correct at compile time, I just want context sensitive editing in an IDE, and that is a less constrained problem.
🍰 2
t
I think for text languages, dynamic typing is better for all the reasons described. Static types are kind of like a mechanism that forces you to write your program in the shape of a proof. For someone just learning and hacking, "formal correctness" is probably not their primary goal; they just want to get something done, and correctness-proving is an impediment to that. Static types are great if you want a complex, maintainable and self-documenting system. That's kind of a different set of needs than those driven by learning. But I think that could flip for a visual system. When type annotation is done for you by the environment, it could stop being a hoop for the programmer to jump through, and start being helpful information from the UI which tells you which affordances are available— i.e., "you can't plug this thing into that thing." I'd sort of like to see a maybe Haskell-ish system in a visual environment, where the type annotations are as narrow as can be proved, and the affordances are as generous as can be allowed. Basically a system that stays out of your way unless it knows there's trouble; the programming equivalent of an active accident-avoidance automotive system.
d
While i know roughly what you mean you say dynamic types and explicitly types. I think its important to note that those terms aren't well defined. As those of you with my experience can probably elaborate on, type systems across languages vary greatly. I always hesitate to poke at this topic. As i know many has spent a lot longer on the on it. But to me, types just invert the problem, but don't necessarily make it more clear. It goes from, what does this function do, to what arguments does this take, which is a function of what this function does. I think carefully done, this extra information (and constraint) can help users. Lots of times, it just seems to introduce another layer of incidentally complexity. if a dynamic language exposed all the oddness that occurs between numbers and operating systems then it would be very frustrating to "learn" basic data science, because the user didn't want a lesson on all that other stuff. Like all tools, context matters and deciding that at the language level along isn't capturing enough of it. We have to be more specific and deiced what we want them to learn about programming.
@Doug Moen what is "context sensitive editing in an IDE" links are fine 🙂
s
@tbabb those are my thoughts as well, I could be off though. Basically if you think of types as puzzle pieces or lego pieces that don't fit when types do not match, I'm not sure if it'd be frustrating for users or empowering. The alternative is to allow automatic type conversion, or I guess explicit type conversion where a new block\piece is inserted that represents the type cast (blueprints does this in some cases)
t
@Scott Anderson Yes, exactly— if you try to plug type A into type B, and there is a conversion available from A to B, that conversion is explicitly inserted for you so you can see it. If you plug a float into an integer, there is an obvious thing you would want to happen. I think it is right to show the user that "something is happening" there by inserting an explicit type conversion operation, since problems might lurk inside of that operation that the user needs to understand. But I also think it would be wrong to explicitly stop the user from doing that. A well-designed user-facing system should defy the user's expectations as infrequently as possible.
👍 1
j
@Jason Priestley While it’s true that type inference introduces complications, it’s at least in part a decision about how to handle errors, and how much effort to put into making errors helpful. I would say that using the term “unification” in the context of a type error is not putting that effort in.
f
What about a language / environment that supports both? You could start writing a program that heavily relies on runtime information (Python-like for example) and if you wanted, you could (assisted by the environment) provide additional information which could then unlock additional things like guaranteed type correctness or performance optimizations.
d
Isn't that the premise of gradual typing?
That was sort of my point, the question of which to use for teaching "dynamic vs static", begs the question, what are you trying to teach. My brother wanted to build a toy application in Haskell, he ended up just learning a lot about how numbers work.
g
My current opinion is that dynamic typing is great for a single programmer making a relatively small program (say 100 to 1000 lines). After that static typing wins. I love dynamic typing when I'm just hacking a small something together like a small animation on a webpage but past a certain size I get lost in my own code. Types basically add computer checkable documentation which is useful both for myself and collaborating. To take dynamic to an extreme. Today, hacking something small, I started with something like this (JavaScript)
Copy code
class Foo {
  constructor(width, height)  {
     this.width = width;
     this.height = height;
  }
}
I then added more parameters and decided I'd rather pass in an object so I can add more and more parameters
Copy code
class Foo {
  constructor(options)  {
     this.width = options.width;
     this.height = options.height;
     this.speed = options.speed;
     this.weight = options.weight;
  }
}
but I realized I can just do this
Copy code
class Foo {
  constructor(options)  {
     Object.assign(this, options);
  }
}
it does the same thing effectively. Yes I know it's dangerous and evil and I'll pull it out but it's tempting because I can add more and more parameters and don't have to write any new code to accept them. But, there is now ZERO documentation 😭
d
I long ago decided that for my language(s), "type" will simply mean "syntax" or "match", and all "types" are in the eye of the beholder: when doing a rewrite, if data matches a pattern, are in a given set or meets some condition, then that can trigger the rewrite. Examples of patterns are
number
,
temperature
,
[ab].*d
,
{1 30 93 }
or
< 100
. This extends beyond simple values up to the shape of more complex structures like hash/map/object and list/array.
the UI can detect common shapes or flags in data and offer autocompletion or highlight apparent discrepancies
d
@gman Can i suggest that the real culprit there is that: 1. Object assign seems to mutate the both the this target and the source. Even if the source is a const (really js?). 2. The properties your assigning probably don't need a custom type/class. You can keep that information by itself and just build functions to handle it. The key "weight" is self documenting, if you want to group that information together variable assignment can do this. The HashMap type has the advantage for holding data here, because it has an API that other users understand, which solves your documentation issue. It also doesn't constrain the users of that information. I think the general issue with using a HashMap here has more to do with the fact its mutable and that people mutate it, then how it behaves in terms of holding information.
d
@Drewverlee "Context sensitive editing in an IDE" means, informally: (1) Editing a literal constant using a domain specific editor (eg, edit a colour value using a colour picker). (2) Context sensitive help for filling in a hole in an incomplete program (eg, an argument expression that you haven't entered yet).
@Drewverlee Static type systems look like a tar pit: you start adding static typing to your language, and you come out the other end with GADTs and dependent types, and 98% of your language complexity is in the type system. But the goal of "context sensitive editing" in my visual language is to make things easier and more convenient for non-technical users. I don't want to go off on a tangent playing with type systems, I want to directly solve the problem of providing context sensitive assistance to a user in a visual programming environment in the simplest way possible.
👍 2
@Drewverlee Curv is a DSL for procedurally generated computer graphics. My first step was to copy a feature from OpenSCAD and Fragmentarium: you can annotate a variable definition with a "picker expression", which specifies a graphical value picker to use for editing the contents of this local variable. For example,
slider(1,10)
constrains the local variable to be a floating point number between 1 and 10, and displays a slider widget for changing the value. Or,
scale_picker
treats the variable as a "scaling factor": it is constrained to be a floating point number > 0 and < infinity, and a kind of logarithmic slider is used to change the value. Even though picker expressions constrain the value of a variable, these value constraints don't necessarily correspond to types in any statically typed language that I know. So it's not clear that a static type system is even the right tool for the job.
y
“driving on roads. Yes, it can be a constraint. You can’t just drive through a river and over a mountain in a straight line from point A to point B. You have to stay on the roads, learn the traffic laws, and so on. But you still get to your destination, and you probably get there faster.”
💯 1
k
Something that has been bothering me for a while in the dynamic-static debate is the absence of application context. In my experience, the added value of static typing depends very much on what you are doing. In particular on the kinds of mistakes that are the most difficult ones to deal with. As an example, in much of scientific computing, most data is "float" or "array of float" and most mistakes happen at the value level (a missing factor 2, an index off by one). Static typing doesn't help much with those mistakes, so its cost (in terms of language complexity) is hard to justify.
d
I find it hard to not become emotionally attached to the tools I use. I'll admit I have become very fond of Clojure as the community has taught me a lot about software. Is Clojure something i should be emotionally attached to? An objective part of me says no, but a deeper part of me knows this is impossible. With that in mind, can i present that a review of large scale study on reducing bugs in programs ranked Clojure, a dynamic language, as doing the best. Ruby, Haskell and Clojure were found to do very well. That's two dynamic languages to one static. https://arxiv.org/pdf/1901.10220.pdf The more important take away, was that if the advantage to static typing is great as some report, then it should surely show a significant difference. Yet no study i have seen, has concluded this. No argument I have heard has given me the clarity to understand why it would be the case either. In a post like https://pchiusano.github.io/2016-09-15/static-vs-dynamic.html that lists pros and cons, i often agree with both lists. However, to conclude that one leads to great efficiency seems short sited. The cons he lists can be used to refute the pros. As the assertion that static types are better, seems to be a wide spread belief in the software community, i often feel compelled to voice an alternate point of view. I believe that we should have the ability to compose the ideas. To drop mentally tracking types in a context where it offers more overhead then it offers clarity and to re-establish them in the inverse.
y
@Drewverlee Maybe there aren’t rigorous experiments, but you can find many telling experience reports. For example in a past incarnation @eyal and me were very much in the Python camp (even though we both mostly used C/C++ in our jobs). Eyal tried to use Python on a non-small personal project - and attempted to implement a projectional editor in Python! His experience with that project in Python was that whenever he wanted to refactor it was a nightmare. He vividly remembered the pain points, and when subsequently he switched to the Haskell camp and tried to implement a projectional editor in Haskell (which is Lamdu) he didn’t get stuck and had much greater success! As for another example - my company’s site soundradix.com is based on Python/Django. One day someone pushed a change which caused a bug and then him and me spent the whole night debugging it. I had to cancel my plans with my girlfriend because of that and that wasn’t cool. And after finally finding and solving it, it turned out that it was something that in any static language would had been quickly caught at development time and not after a day of debugging after it was deployed, and would not require cancelling any personal plans on short notice. That was a case where it was obvious how static types could had improved my quality of life.
d
@yairchu I think i understand where your coming from. I agree it's the case that static types can give insight into the code and in doing so prevent errors. I think its one tool among many others that we can apply to that effect, but i'm not at the point where i personal believe its a tool that universally improves my ability to reason or prevent errors. Maybe how its applied matters greatly. By linking to a study, that finds no strong correlation between bugs and static typing, i hope to motivate the discussion about why and how types help, rather then glossing over that and going straight to why can't we convince everyone to use them.
a
one of my favorite writings on the topic: https://gist.github.com/non/ec48b0a7343db8291b92 this really resonated with me when trying to the nuances of type-level programming in Scala. dynamic languages permit techniques that are very difficult to model in static type systems, period, let alone in ways that the types are comprehensible. i think we're making a lot of progress toward type systems that can do this increasingly well. Scala goes a long way towards trying to let you write dynamic-looking code with static types. TypeScript comes from the other direction of trying to model idiomatic JS in a type system. but in both, the type system operates quite differently from the value system, which makes it hard to grasp. that said, i'm generally a fan of static types, at the cost of sacrificing some of those hard to model techniques
👍 1