loading...

What are the benefits of dynamic typing?

yujiri8 profile image Ryan Westlund ・1 min read

Okay, when I was first learning Python at 15 I pretty much thought static typing was stupid. But I was dumb. Ever since I learned to appreciate static typing when I learned Go, I've seen it as pretty one-sidedly better. Even the only thing I could think of over the years that seemed to make an argument for dynamic typing, people pointed out in the comments that some languages' type systems could actually solve it just as well (just not any I know).

I think all the legitimate gripes people have with type systems are just with bad type systems, and if you combine the good ideas from a couple of them, you can easily imagine a type system with all of them benefits and none of the costs:

Et cetera. It seems every problem caused by one language's type system is solved by another's, and there's no reason their good traits couldn't be combined. What are the counterexamples?

Posted on by:

yujiri8 profile

Ryan Westlund

@yujiri8

I'm a programmer, writer, and philosopher. My Github account is yujiri8; all my content besides code is at yujiri.xyz.

Discussion

markdown guide
 

I think the inherently difficult part of all this is that any programming language needs to be intuitive, and type systems tend to vary dramatically in this sense based on lots of implementation details.

The idea of "intuitiveness" has a lot to do with average past experience and stuff that becomes somewhat "standard", even if it's not inherently intuitive.

Of course, how the type system interacts with the popular IDE/tooling is also a big deal. It's hard to think of any of this as too much of a vacuum.

 

Duck typing and deserialization. When you want to prove the system wrong, and that it doesn't know everything. Also, when you received data from external sources.

 

I think duck typing is compatible with compile-time type checking. Haskell has very powerful type inference and can deduce the argument type of a function to essentially be "anything that these functions can be used on". Although I don't know of examples, I think it could be extended to essentially define interfaces implicitly.

Even Go mostly supports deserialization with static typing. At worst, you need to add some struct tags to map JSON or XML names to struct fields - but you'd have to do that anyway unless they already match. And as for data from external sources, I used to make that point too, but wouldn't you normally have a defined structure you expect? Every time I'm doing something like reading a JSON object, I'm expecting a Customer, or the arguments for posting a Comment, or something. I'm sure there are situations where you need to parse a serialized object of arbitrary structure, but even statically typed languages can do that with token/event-based parsers. Sure, they kind of suck to use, but just how common is that?

 

So, I guess the real answer is laziness / ease of use. You just want the job done, and don't have to be explicit (which actually bad in the end, when you write tests).

Long ago, I wrote about escaping strong typing in Kotlin (with JSON serialization / deserialization).

I don't like Python and JavaScript, indeed; but they do have merits -- existing libraries.

TypeScript has both pros and cons. It integrates well with the IDE, but it is both (still) weakly-typed and dynamic-typed. It sucks when there is no runtime type-checking, unless you go extra miles...

In the end, it depends on your experience, and what you have been taught (availability of learning material), actually.

 

I just wrote a whole article that kinda speaks to some of the "problems" that can occur when moving away from dynamic typing. (dev.to/bytebodger/key-headaches-in...)

But I wanted to comment here because your title speaks of dynamic typing versus static typing. Yet, that's not the only kind of typing. It's not necessarily a Boolean between static-or-dynamic.

I've done enough Java & C# that I'd never try to yell anyone down about the benefits of static typing. Although I'm almost exclusively a JS dev at this point of my career, I can freely admit that there's much to enjoy about static typing. And if you're firmly ensconced in that paradigm, it's borderline-useless to try to argue against static typing - thus, I wouldn't even bother.

When it comes to strong typing - e.g., TypeScript - there are definitely some... headaches. Specifically, I've become rather annoyed any time I feel as though I'm forced to explain, to the compiler, exactly what my perfectly-functional code is doing.

In statically typed languages, this never bothers me. Because, in a statically typed language, if your IDE is giving you that "red squiggly", it's not just "complaining" about your code. It's pointing out something that simply won't work.

But when you're dealing with strong typing systems, there are definitely times when the IDE/compiler is complaining about code that actually runs. That can be... frustrating, to say the least.

 

I suppose I might not've used the right terms. I'm not really clear on the difference between static and strong typing. When I say dynamic typing, I'm really thinking of "systems where types are never checked", like Python, where you can put an int inside a list of strings, or pass the wrong type to a function and not find out until you try to use them and the error message is something like "'int' object has no attribute 'lower'" when it would've been more helpful to see "cannot append 'int' to list of 'string'" earlier.

As for the TypeScript examples you give, (I've never used TypeScript) they seem like a bug. Why doesn't TypeScript know that Objects can be indexed by Strings?

 

there's no reason their good traits couldn't be combined. What are the counterexamples?

I think what is happening is that we conceptually don't know what is good or bad about each type system component. One of the goals of a language designer choosing to include a type system is because they want to enable building structure for code.

I think templates (C++ kind, not the web kind) are probably what you mean by interface inference. They can allow any type to be passed in and the compiler will complain if the operations are invalid for that type.

But the Go designers did not believe this provided enough structure, so the made an interface system that checked the types interface. The value here is more about the function being relegated to a subset of operations for the type.

Class explicit inheritance for interfaces are chosen so that the class designer is given compiler errors if they don't meet the interface.

 

You're making me want to learn C++ :)

 

No just use D, though I don't call this good coding.

struct Customer {
    auto email = "me@example.com";
    auto phone = 555_655_2896;
   } 

void main()
{
   
   auto field = "email";
    
    Customer customer ;

    switch(field) {
    case "email":
         callFunc(customer.email);
        break;
    case "phone":
         callFunc(customer.phone);

        break;
        default : break;

    }
}

auto callFunc(Thing) (Thing t) {
    import std.stdio;
    writeln(t);
   } 

Or

void main()
{
   enum field = "email";

    Customer customer ;
    mixin("callFunc(customer." ~ field ~ ");") ;
}

Whoa, you can do that in D? Cool!

 

Dynamic Typing is useful when you have to work with Maths and Stats because the type changes every time and it becomes easy for the user.

 

If I correctly understand what are you referring to - reusing same variable name - then there is no need to have dynamic typing for that. Rust uses 'name shadowing' and achieves same convenience within bounds of static typing.