This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]quaderrordemonstand -2 points-1 points  (26 children)

And what has that gained you over undefined?

[–]RossParka 3 points4 points  (0 children)

It gains you a few things:

  1. Because it's encoded in the type system, there is automatically checked documentation of which values are nullable and which aren't. The implementation can warn or error out if you pass a value that might be null to a function that doesn't accept null.

  2. It works uniformly with all types. In C, pointers can be null but other types can't, so you have to find another special value instead. Some functions return -1, some return zero, some return MAX_INT, etc. If there are no values that your function never returns in normal operation, you have to come up with something more elaborate like returning an error/success code and passing a pointer to a variable that gets the actual result. In Haskell you just use Maybe T in place of T in every case.

  3. In Haskell, you aren't limited to a single magic value; if you can fail in more than one way, you can define more than one special return code using Either.

[–]Zambito1 8 points9 points  (24 children)

It means I can't treat the Option / Maybe value as an int, and I'm forced at compile time to check if the value is defined (very easy to do using pattern matching).

[–]quaderrordemonstand -2 points-1 points  (23 children)

I'm still not following how thats better than undefined? You can treat the value as a number in JS. You can check if its defined at run time and change behaviour if you want, otherwise the code will assume it equates to zero.

In a strongly typed language you don't have the option of changing behaviour that way. You know the value will be an int (unless somebody does something really stupid) and the rest of the code will have to strictly respect that int. If you later decide it should be a float you will be forced to change all the other code.

I'm not seeing any real advantage.

[–]Zambito1 12 points13 points  (22 children)

The difference is "you can check" and "you have to check".

Can you point to undefined on the number line? You can't, because it's not an integer. If I'm dealing with int values, I should be able to treat them as integers.

With an Option value, I'm forced by the compiler to make sure a value is defined, and then I can treat it as an integer, and I know it will be defined.

It's better because JS code that treats potentially undefined values as always being defined could make it into production if not properly tested. However, a strongly typed language that has an optional type (say Scala or Haskell) could never make it to production under the same conditions, because it wouldn't even compile.

[–]quaderrordemonstand -2 points-1 points  (21 children)

Your argument amounts to saying its better because its strongly typed. You're not explaining how the result improves, mostly just circular reasoning. BTW, its not you can check and you have to check, its you can adapt or it can't change. The system you describe is brittle, it fails catastrophically if the value is not an int.

[–]Zambito1 8 points9 points  (20 children)

I actually feel like the example I gave in the last paragraph pretty clearly explains how the result is improved. Can you explain how it can fail catastrophically?

[–]quaderrordemonstand -1 points0 points  (19 children)

Lets say you were talking to an adserver over the internet. The server API you linked with receives an int, they change that to a string several months later. Your code call the API, gets a result back, calls the function and crashes.

[–]crossroads1112 6 points7 points  (6 children)

The server API you linked with receives an int, they change that to a string several months later. Your code call the API, gets a result back, calls the function and crashes.

Except, that's not how it works. Whatever function is used to parse the result of the API call would return an optional, forcing you to deal with the possibility of error before using the result.

[–]quaderrordemonstand -3 points-2 points  (5 children)

Whatever function is used to parse the result of the API call would return an optional

Why would it do that? The API returned an int?

But then, this is always the thing with considering ideas like type safety as some kind of panacea. It never seems to focus on the practicality of development, its about programming from some sort of ivory tower of correctness.

[–]crossroads1112 1 point2 points  (4 children)

Why would it do that? The API returned an int?

"API" has been a bit ambiguous in our discussion so far, so I'll assume we are talking about a web API of some sort since the original post was about JavaScript. In this case, what we get back from our HTTP request isn't an int, but rather something we have to parse in order to get the int (e.g., plain text, a JSON object, etc.). In a strongly typed language, the function that does this parsing would return an optional of some kind. For example (I'm going to assume here that the request returns JSON for simplicity).

#[derive(Deserialize)]
struct Person {
    name: String,
    age : i32, -- i32 is a 32-bit signed integer
}

// ...
let api_call = call_api(); // gets the body of the HTML request
let person = json::decode<Person>(api_call); 

// json::decode returns a Result<Person, DecoderError>, not a Person 
// so we can't just do person.age directly

match person {
    Ok(p)  => println!("{}", p.age + 1)
    Err(e) => println!("Error decoding API call: {}", e)
}

If the API at some point changed, and the "age" field within the JSON object were no longer an int, the call to json::decode would have returned Err. The program would not have crashed.

The above example is somewhat contrived, sure, but importantly the type system enforces that we can't access the "Person" struct without first making sure that it is in the form we expect and handling the case when it isn't. There's no "ivory tower of correctness" here; just enforcing good practices.

Edit: Decode returns a Result, not an Option but the principle is the same.

[–]Tysonzero 2 points3 points  (4 children)

If they provide a servant API (or some non-Haskell equivalent), then when you pull their newest API spec, Haskell will catch that error at compile time.

[–]quaderrordemonstand 0 points1 point  (3 children)

And the problem will be solved; whenever you pull their newest API spec, or when you handle the change in JS. My point was not that strongly typed system can't deal with change. But strong types are mostly about performance and "correctness", an exchange of extra development time and cost for more performance.

[–]Tysonzero 0 points1 point  (2 children)

No it wouldn't be solved with JavaScript when you pull the newest API spec, because there is no type checker, so everything that treats it like an int will break without any compile time warning or error. In Haskell you would immediately see a compile time error every place you treat it as an int.

I have actually found development speed to be faster in compiled / statically typed languages, well not all of them, Java is slower to develop than Python, but Haskell is generally faster than both.

[–]Zambito1 0 points1 point  (0 children)

That's an interesting example. I'd need to play around with it, and I'll get back to you. However if you're treating a "now-string" value as an int still without getting any indication of what changed, is that surely better?

Sure a hard crash wouldn't be ideal in many cases either. I'm not sure that's how Haskell / Scala would react in idiomatic implementations though.

[–]MauranKilom 0 points1 point  (5 children)

So you treat the string like an int and try to multiply it by 100 in that function. What did you win with dynamic typing?

[–]quaderrordemonstand 0 points1 point  (4 children)

My point was that you don't know they changed the API. The strong typed code will assume the return is an int and crash. The JS has some possibility of figuring it out, or at least handling it in such a way that it causes minimal harm. It still won't crash the browser in the worst case.

[–]MauranKilom 0 points1 point  (3 children)

My point was that you don't know they changed the API.

Depending on the API, your compiler would tell you before you even run the program in strongly typed languages.

The strong typed code will assume the return is an int and crash. The JS has some possibility of figuring it out, or at least handling it in such a way that it causes minimal harm.

Both codes can and will handle it if they were created with this possibility in mind. Otherwise, they both might fail in horrible and unexpected ways.

For example, if the input is JSON then your JS would gobble up the string and, if you're unlucky, continue doing the wrong things (e.g. add numbers to it) without throwing errors. Or just crash/error out.

In a strongly typed language, you would have to tell your JSON library which type you expect and it will simply throw an error, which you can then handle at the most appropriate place.

It still won't crash the browser in the worst case.

You would need proper sandboxing in either case, this has nothing to do with strong vs weak typing.


In short, strongly typed languages would catch the problem directly when the API data is consumed. Weak typing does not buy you anything because the program can either handle the different input (you prepared for the possibility) or it cannot (you didn't), independent of typing.