TypeScript 0.9 language spec 4.15.6 (&&) is surely wrong.

Topics: Language Specification
Jun 20, 2013 at 5:04 AM
I quote: _The && operator permits the operands to be of any type and produces a result of the same type as the
second operand._

This suggests that (0 && "abc") should have type string, but of course, it doesn't.
Jun 28, 2013 at 6:05 AM
Where do I have to ask to get an answer?
Jun 28, 2013 at 3:06 PM
Edited Jun 28, 2013 at 3:08 PM
Not sure that I understand your question.

Did you want TypeScript to figure out that 0 will evaluate to false and therefore have the result of (0 && "abc") to be number?

And for (1 && "abc") TypeScript would have to figure out that 1 would not evaluate to false hence have the result be string.

What about
var x = 0;
var foo = x && "abc";

Jun 28, 2013 at 6:20 PM
I think the fix is simple... if both operands are the same type, then the resulting value is that type. Otherwise the type is any, unfortunately. The current spec doesn't make sense.
Coordinator
Jun 28, 2013 at 6:27 PM
Edited Jun 28, 2013 at 6:42 PM
The type of the left operand is mostly irrelevant because if you get a value that came from the left operand, it's guaranteed to be falsy. The domain of falsy values between two arbitrary operands already overlaps for the important values (null and undefined), and it's really unclear why you would care for the values that lie outside that intersection ("", NaN, false, and 0).

It's very difficult to write non-degenerate code where this rule isn't correct for all practical purposes.

See also http://stackoverflow.com/questions/12693787/why-does-the-operator-produce-the-type-of-the-second-operand/12694771#12694771
Jun 28, 2013 at 11:16 PM
Ryan, thanks for your reply.

Two responses. First, the type rules should work for all legal code, not just idiomatic code. Second, in our code base we do indeed have instances of the left argument being in your nonintersecting set and this has led to bugs. Here's an example: a.length && a[0].x. We want the type checker to catch these cases.

Here's the thing: given that the type rules for && and || are just wrong, is there any chance I can convince you (the TypeScript team) to fix them?

Possible useful compromises could include the addition of new, well typed, logical operators for TS.
Jun 28, 2013 at 11:24 PM
Hi Nabog, in the general case, if the argument types differ, the result must have type any. Claiming the result type is always that of the right argument is obviously wrong in general.
Jun 29, 2013 at 5:54 AM
@ralphbecket,

would you care to provide more details of your example? Specifically, about the context: how exactly are you using the value from the assignment?
var a = [{x: 10 }];
var aVal = a.length && a[0].x; // aVal is either 0 or 10, both numbers

var b = [{x: "string" }];
var bVal = b.length && b[0].x; // bVal is either 0 or "string"
TypeScript infers bVal to be string, but it can be number at runtime. But to me the second example doesn't exactly smell brilliant.
Jun 29, 2013 at 6:08 AM
@nabog

It's irrelevant that the code "smells wrong" (little disagreement from me there, but the whole web world is slightly whiffy), the fact remains it is legal code and the type rule predicts the wrong type.

Personally I'd prefer it if TypeScript forbade non-boolean arguments to logical operators altogether, but I know that would never fly with the community.

However, a type system that is wrong really is a serious problem. The point of a type system is to exclude an entire class of errors from your programs. As it is, I'm wondering now whether there are other idiomatic land mines in the TS spec. other than just && and ||.
Jun 29, 2013 at 6:19 AM
You know what we need to solve this problem? New operators! &&& and |||. Those operators produce a value of type 'any'. You can send my payment via PayPal. /sarcasm

Andrew Gaspar


Jul 3, 2013 at 2:52 AM
Silence, again?! I'd have thought an error in the type system would warrant some action.
Coordinator
Jul 3, 2013 at 4:01 AM
It's understandable that some will prefer a type system more oriented toward theoretical concerns than practical ones, but we have seriously looked at the alternatives and consider this the best available option at this time. It's impossible to impose a perfect type system on top of a language like JavaScript and the trade-off we made for && is one that the vast majority of code will be better off with.
Jul 4, 2013 at 12:40 AM
Hi Ryan,

thanks for your reply. I confess, I've never considered correctness as anything other than a practical concern. Other than && and ||, are there any other cases you know of where the TypeScript spec. is "wrong, but 'pragmatic'"?

I was really hoping TypeScript was a serious attempt to get away from the laissez faire JavaScript world -- debugging this stuff is unbearably tedious. Is there any chance you will add properly typed variants of the logical operators (&&& and ||| have been proposed)?
Jul 4, 2013 at 10:07 AM
@ralphbecket,

it seems slightly hypocritical to say on the one hand that it's okay to write code that is "whiffy" and on the other demand that TypeScript deal with the consequences of badly written code.

In a relatively large code base (of some tens of thousands of lines) we've never encountered any bugs from TypeScript having inferring the type from the second operand. Perhaps it's because we do not tolerate "whiffy" code.

Conversely, if TypeScript only inferred any then it is probably likely the lack of type information would have introduced a bug or two - actually, considering how common this pattern is it's more than likely.

So we would not like to see this behaviour changed.

I'd be surprised if you agreed with me on this (especially in the light of my holier than though attitude!) so I think it's best we agree to disagree on this.

Noel
Jul 4, 2013 at 12:36 PM
@nabog

I must have misled you: I've never considered it acceptable to write whiffy code (we need a better term!) and I don't expect TypeScript to do anything with badly written code other than reject the ill typed parts.

As far as I'm concerned, a type system allows the compiler to prove things about my code. In particular, if the compiler "proves" that expression e has type number, say, then I expect e to never evaluate to something that is not a number. Imagine my surprise when, one day, e gives me a boolean back!

By introducing type rules that are "wrong but 'pragmatic'" you throw out the very guarantees I, as a software engineer, was hoping to depend upon.

I can accept, even if I disagree with it, that pragmatically (i.e., you'd otherwise lose 99% of your user base) you chose to allow values of type any to be silently assignable to variables of arbitrary type. Who knows, maybe one day there's be a compiler option that will reject such horrors. Frankly, I doubt it: it's too easy to abuse and almost none of the TypeScript code base would survive such a restriction. On my project, I see developers bitten on a daily basis by this noose-like piece of rope. But that's an argument for another beer.

However, and here's the key point, the very fact that you added types to JavaScript says you do intend TypeScript programmers to change their programming habits from JavaScript, where anything goes. Given that, I see nothing inconsistent with expecting people to show more discipline when coding up conditions and conditional expressions in TypeScript than they would need for JavaScript. Good heavens, it's a superset: you can even add new syntactic sugar to provide principled, sound, convenient solutions for these ubiquitous half-arsed JavaScript idioms.

You might not tolerate "whiffy" code where you work, but I assure you that in many teams there are well meaning developers unknowingly producing just that at a rate faster than those of us who grok type systems can keep up.

All the best,
-- Ralph