3 ms·
In dynamic languages, like Python, all variables have a static type of "Any", so "5" == 5 has matching static types. Then the runtime types (or tags as some pre
by simiones 5y ago
In dynamic languages, like Python, all variables have a static type of "Any", so "5" == 5 has matching static types. Then the runtime types (or tags as some prefer to call them) are checked in the implementation of == itself. This is perfectly equivalent to what must happen in your example with `a in b`. Python can't express something like Int[], though.
- kennywinker 5y agoI've spent a lot of time with languages that use runtime enforced types, and then a lot of time with compiler enforced types. The latter is just better. We can argue about how strict the typing system should be, how much it should guess at types or coerce types, etc. But there is no world where `"5" == 5` shouldn't at very least throw up a warning to let the programmer know that STUFF is happening here that you might not expect.
- int_19h 5y agoThis isn't a function of static vs dynamic typing, though. You can write "5"==5 in Python, because, while == is always value equality, the root class provides a default implementation for it that simply checks the reference. They could have made that default implementation raise an exception, though. I believe the main reason why it doesn't, is because it allows to write kinda sorta generic code that always uses == for comparison, and have it work for the most common cases for both value and reference types (defined semantically here: reference types are those where object identity matters in some way, value types are those where it doesn't). For example, functions that work on lists, or even the standard operator "in". If not for this hack, everything that needs to compare things would have to take an explicit comparator function for every separate comparison context to ensure that caller can request "==" or "is" as appropriate for their use case. FWIW, I believe that explicitly parametrized comparisons should be the norm in generic code, not exceptions, even if it's more verbose. But mainstream PL design hasn't really embraced this. Much like how we keep repeating the mistake of making strings indexable and iterable without specifying what is being indexed or iterated (bytes, codepoints, graphemes etc) - because programmers are so used to the convenience of doing that, not because it was ever a good idea.
- kennywinker 5y ago> They could have made that default implementation raise an exception, though. That wouldn't be an improvement, tho. Runtime exceptions mean you have to exercise that code-path to find something as trivially detectable as comparing a string to an integer. It has to be a compile-time check (or a validation step for an interpreted language). To specifically address your scenario: > If not for this hack, everything that needs to compare things would have to take an explicit comparator function for every separate comparison context to ensure that caller can request "==" or "is" as appropriate for their use case. This is a solved problem in statically typed languages. All it takes is a protocol/interface called "Equatable" or "Comparable" or something like that. Collection.contains is only available if the collection's contents implement that "Comparable" interface/protocol. For every comparable thing, == is a required fn. A good clear example of this is `equatable` in swift https://developer.apple.com/documentation/swift/equatable https://developer.apple.com/documentation/swift/equatable Swift takes the stance that nothing is Equatable unless it opts into the protocol. It also synthesizes a definition of == if the type is simple enough. Another language might say, ok everything is equatable, the default definition is just comparing memory addresses (a->ptr == b->ptr) - but that would still require a and b being of the same type. If you want to compare an Apple and an Orange `==` is the wrong tool. Something like `apple.sameCaloricContent(orange)` i.e. a function that describes how you're comparing two un-alike things would be the right way to handle it.
- int_19h 5y ago> That wouldn't be an improvement, tho. That would be an improvement, surely? Just not one that is good enough... But at that point we're discussing a much broader problem (or feature, depending on who you ask) with dynamic typing in general, which is different and orthogonal to the problem with implicit conversions that "5"==5 is all about: whether it's an error in the first place or not. > This is a solved problem in statically typed languages. It's only a solved problem if you follow the patterns consistently, which many modern languages do not (e.g. look at C# and Java, which have == and Object.Equals() and Equatable, and where collections of equatable items aren't themselves equatable). But even then, it doesn't really solve the "contains-problem", because the request is ambiguous by the very nature of a collection of references - perhaps you do, in fact, want to check if a reference to an object is present in the collection or not, rather than checking for something that is value-equal. This also goes for comparing whole collections for equality element-by-element etc. All those cases, at the minimum, need a way for the caller to specify which kind of comparison they need. Worse yet, there's no clear default here - both are common - so, ideally, it should always be explicit.
- simiones 5y agoEquality in particular is a tricky subject with languages that have reference types and subtypes. Even C# and Java define equality between all types ("5".Equals(5) is false, not an error). Still, I wasn't trying to defend dynamic typing over static typing, just pointing out how to conceptualize the dynamic language decision in terms of type theory, to point out that it's not surprising.