9 ms·
I am interpreting the term "library" somewhat broadly -- my notion is that int isn't conceptually any more core to the language than e.g. the numpy matrix class
by zenhack 8y ago
I am interpreting the term "library" somewhat broadly -- my notion is that int isn't conceptually any more core to the language than e.g. the numpy matrix classes. It's built-in for speed, but (apart from some syntactic sugar for literals), it's semantically just another class. In this light, the distinction is happening in the code that defines the int class, not in something deep in the language semantics.
The call to str isn't really a cast (which doesn't really have a counterpart in a language without static types); you're calling the constructor to the str class, which somewhere in it has a code path where it formats an int as a string (probably by way of calling the argument's __str__ method).
- joshuamorton 8y agoSure, but int being core or not is totally irrelevant to whether or not the language attempts to convert things for you. If int was auto coerced to strong that would be one thing, but in weak languages, everything is coerced to everything when it might make a modicum of sense, even in user defined types. Literals become strs, objects become strs, strs become ints, arrays and objects can be combined Willy nilly leading to unintuitive results. And since your object inherits from one of those things, you are stuck with that too. The language forces you into weakness. Yeah okay you can jump through hoops to make your api kind of weakly typed in Java or python, but well it probably won't work in general, because the attempts to coerce will probably fail because the language doesn't know how to understand them, because the two types are incompatible. And unfortunately for your argument, not every type can be a library. Object has to be provided by the language itself. So the question becomes, can you freely coerce between the base object type and another without loss of information. If yes, weak. If not, strong. Python: strong. Js: weak.
- zenhack 8y ago> Object.prototype.valueOf = function() { throw "I will not be coerced!" } > 4 + {} Thrown: I will not be coerced! This doesn't seem fundamentally different from overriding getattr. What you've got in Js is basically a handful of pre-defined functions with some syntactic sugar, which are bone-headedly written to go out of their way to not report problems. But this really isn't any different than higher level libraries like nodemailer, whose attempts to be smart have been the source of vulnerabilities before: https://sandstorm.io/news/2017-03-02-security-review https://sandstorm.io/news/2017-03-02-security-review The impact is the same, and your options for mitigation are the same. Also, fwiw, Python has some questionable decisions in the basic "libraries" too: >>> 4 * '5' '5555'
- joshuamorton 8y ago>This doesn't seem fundamentally different from overriding getattr. Right, but you can't override Object.__getattr__ in python. That's basically where the difference lies. In python, `object`s don't naturally coerce, and you cannot force them to coerce. In js they do and you can. Of course in any language you can write a badly behaved object that implements an interface that it really shouldn't, or in a way that is unexpected, but that isn't weak typing. >Also, fwiw, Python has some questionable decisions in the basic "libraries" too: Right, but even this isn't weak typing. It might be an interface you disagree with, but its very explicitly written to work this way. Compare that, again, to a weakly typed language like JS where you can multiply a string by anything, and you'll get NaN instead of a type error. In python on the other hand, `4.3 * '5'` gets you a type error, because you can't have a 4 and 3 tenths character string. Basically, the difference between what python does and what js does is that python says `* ` is an operator implemented on a left hand and right hand object. So for `l * r`, I first attempt to see if the left hand object knows how to multiply itself by the right hand object (`l.__mul__(r)`), and if that works, great. Otherwise, I check if the right hand can multiply itself by the left (`r.__rmul__(l)`), and if that works, great. Otherwise, these don't match, so throw an exception. This is strong typing, where every object decides, for itself, which other objects it is compatible with. You can certainly write an object which is compatible with anything, but up to you. You get to decide which objects you are compatible with, you're not forced into an all or nothing situation. JS on the other hand says `* ` is an operator defined over things of type number, so to make `* ` work, I will implicitly convert the left and right hand sides to numbers (by repeatedly calling `valueOf`, and then multiply whatever I get from that. The language decides what you are compatible with, and how. You can't just be compatible with numeric types, if you want that, you're gonna be compatible with arrays and objects too, and there's nothing you can do about it. The difference, to put it simply more simply, is that python (and strongly typed languages in general) doesn't have valueOf. You're confusing strong typing + operator overloading with weak typing, and those aren't, at all, the same. The difference becomes clear when you take your example (with the no-coercion object) and try to add an array and an int. The Object's error gets thrown. In python, it would be possible to have a list's __add__ handle an int by appending it. But by extending for another list. In JS, that's impossible. That's because what python and Js are doing are different. Python defers to each type for how it wants to handle other types, but allows them to say "nope, this isn't valid". Js doesn't do that, either you are incompatible with anything ever, or you are compatible in ways neither you nor the other object you are working with can control.