8 ms·
My Opinion on “5” == 5
- withinboredom 5y agoIn php, this is also true or false if you have strict types on. I’d argue that there are some valid use cases for “5” and 5 to be equal. For example, if you take user input where on an admin screen for a user ID or username, you don’t know if the type is a string or number. Another common example is when you don’t have a known encoding for a packet yet, so you treat it as a binary string. In these cases, it’s easier to grok, as a human what is expected.
- Koshkin 5y ago> it’s easier to grok, as a human People usually understand the difference between "cat" and a cat.
- lexicality 5y agoIf you're dealing with user input, you should always be validating the type before working with it. If you want to compare input to an int, you should be verifying the input is a valid int before comparing it. Just hoping the language will do the right thing is a great way to inadvertently allow exploits in your service
- tyingq 5y agoThere are several languages where this sort of type coercion exists. Javascript, Awk, Perl, Tcl, and PHP as you mentioned. For the most part, the developers in those spaces seem to know the pitfalls and how to avoid them.
- smnrchrds 5y agoSo that's why some websites fail to log you in with numerical usernames and/or passwords that start with zero.
- llimos 5y agoPHP also has a nice thing I wish more languages had, which stops you shooting yourself in the foot due to this - the concatentaion operator (.) is different from addition (+). So "5" + 1 is 6, just as 5 + 1 is 6.
- perl4ever 5y agoI can't think offhand of a language that does overload + for strings by default. Perl uses . Oracle SQL uses || Microsoft SQL and VBA use & C obviously doesn't use +. Neither does Pascal. Power Query doesn't.
- Zababa 5y agoJavaScript, Python, Ruby, Go all use +.
- Frondo 5y agoC# does, as do quite a few others. Heh, this is kind of interesting: https://www.rosettacode.org/wiki/String_concatenation https://www.rosettacode.org/wiki/String_concatenation
- rspeele 5y agoC#, GoLang, Javascript, Python, and Ruby are several. Python and Ruby even overload *, for the dubiously useful construction: "hello" * 3 == "hellohellohello"
- infogulch 5y agoI like Julia's standard string concat which subverts a Python user's intuition: "string1" * "string2" == "string1string2". Why? Because monad.
- dahfizz 5y agoJava and Python, from the top of my head, allow "str1" + "str2"
- poizan42 5y ago
- crote 5y agoOn the other hand, what about "V" == 5? Or one of the literally dozens of unicode characters representing the number five in different writing systems? Maybe even "five" == 5? Accepting both a numerical user id and a username string is a very valid scenario. However, I believe you should handle that by explicitly trying to parse it as a number, not hoping that automatic coercion will do the right thing. It's just a footgun waiting to go off.
- tetha 5y ago> Accepting both a numerical user id and a username string is a very valid scenario. However, I believe you should handle that by explicitly trying to parse it as a number, not hoping that automatic coercion will do the right thing. It's just a footgun waiting to go off. This is why many people recommend questioning the use of basic or naked types. Details vary between the language, but this should be a type UserID with a UserID::from(String) and maybe a UserID::from_symbolic_name(String) and everything but some edge code should work on UserIDs. This makes code easier to read, too.
- infogulch 5y agoGood point. "5" == 5 "⑤" == 5 "⑸" == 5 "⁵" == 5 "𝟝" == 5 "𝟓" == 5 "𝟻" == 5 "V" == 5 "Ⅴ" == 5 "𝍸" == 5 # https://unicode-table.com/en/1D378/ "𐄋" == 5 # https://unicode-table.com/en/1010B/ "৫" == 5 # https://unicode-table.com/en/09EB/ If you think the first should work, you should justify why the others shouldn't.
- Y_Y 5y agoWhat about "" ==
- croddin 5y agoSyntax error. Unexpected end of line.
- deleted 5y ago[deleted]
- hprotagonist 5y agoI would accept False. I would also not complain if a "Warning: why are you comparing strings and integers" was raised. Operators like +,-, ... should raise TypeError, or similar.
- samatman 5y agoI like Lua's solution to this dilemma: 5 == "5" -- false 5 + "5" -- 10 5 .. "5" -- 55 It's just dynamic enough, none of the conversions are surprising and they're frequently helpful.
- staticassertion 5y agoWow this is actually the worst solution I could imagine.
- samatman 5y ago...why though? 5 and "5" are different objects, one is a number and one is a string, they shouldn't compare for equality. + in Lua is only addition, you can't add a string to anything, so if that string can be a number, that's obviously what was intended. Similarly, .. is only concatenation, so if you're concatenating a number you clearly want it to be a string. It works great in practice. How is this better than anything which languages that overload addition and concatenation can offer?
- int_19h 5y ago"Shouldn't compare" is not the same as "should compare but return false".
- nybble41 5y agoIf you could do relative comparisons like "5" < 5 and get a boolean answer, that would be surprising. I don't see anything controversial, however, about unequivocally reporting that objects of different types are unequal. In Lua anything can be tested for (in)equality but asking whether a string is greater than or less than a number is an error, as is performing an ordered comparison involving any other type(s).
- nybble41 5y ago> if that string can be a number, that's obviously what was intended Maybe that would be a reasonable assumption in a world where programmers were omniscient and never made mistakes. In practice these "do what I mean" rules just tend to make it easier for poorly-specified programs to produce nonsense without signaling that anything is wrong. If your program intends to add two numbers and one of the inputs turns out to be a string then someone gave you bad input; the right solution to that is to report an error, not continue with bad data. Perhaps it's only an accident that the string happens to look like a number this time. Maybe it wasn't intended to be a number at all, and some parameters got swapped or an input file was corrupted. Also, that rule is too broad. The string "5" could be treated as a number, sure, but so could "five" or "⑨" or "¾". So why is "five" + "⑨¾" an error and not 14.75 (or even "14¾")? If you want to accept number-like strings as numbers, fine, but there should be an explicit process where the programmer defines exactly what form the input can take and how to perform the conversion to a number. Implicit conversions skip that step and expose the internal defaults of the language to the end user.
- nathanaldensr 5y agoIMO, any language with a type system should enforce comparisons only between those types (or derived types) unless a developer explicitly overrides an operator--and even then, overriding operators is sometimes considered bad practice due to violating the principle of least astonishment. The types of a comparison operator's operands matter because the type system exists. Allowing things like "5" == 5 suddenly introduces human expectations of logical equality--"they're both '5', therefore they're equal." Programming languages shouldn't codify these human interpretations. My favorite language, C#, has some unfortunate history. The == operator when dealing with references indicates reference equality (Object.ReferenceEquals), but can be overridden to indicate value equality (Object.Equals) even with reference types. Then, when dealing with value types, == suddenly means value equality. It would've been better to define two separate operators for reference and value equality. This would've helped make usages self-documenting.
- egeozcan 5y agoThat historical... erm... glitch... in C# is very unfortunate and burned us many times back when I was working in a .NET shop (people getting creative was usually the culprit). I've even seen some codebases where people decided to implement their own equality operators (lesson through experience: don't do this).
- coding123 5y agoThey picked that up from C++
- int_19h 5y agoThey picked it up from Java, which also used == to mean both reference equality and value equality. But C# also tried to improve on Java. One of the things that the latter was commonly criticized for, was the need to use .equals() for strings for value comparisons - which is almost always what you want - and avoiding the more obvious ==. So they overloaded == for strings to mean value equality, while retaining them as reference types. IMO, the bigger mistake here was to keep strings as reference types - they really ought to be value types (the implementation can still wrap a reference to the actual string data internally, and share it between copies, but the client shouldn't be able to observe that).
- kennywinker 5y agoThe only acceptable answer is a type error. His example of python being able to handle heterogeneous collections is fine, but a good language will make you be explicit about the types. let a: String = “5” let b: Any[] = [5,6,7] let c: Int[] = [5,6,7] a in b // false - we don’t know what’s in b so we check and a is not in b a in c // type error - there’s no way a is in c. Convert a to an Int, and handle the error cases involved in that.
- simiones 5y agoIn 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.
- vehemenz 5y ago"5" == 5 evaluating to true is only a problem if you don't understand how to do a strict comparison. It is conventional in PHP and JavaScript to use === unless there is some reason not to.
- infogulch 5y agoThe author is right, the answer should be a type error. If you want to compare them as ints, convert the string to an int first (and deal with the potential failure in the case that the string does not represent an integer). If you want to compare them as strings, convert the int to a string first. There are multiple approaches to transform this invalid comparison into a valid comparison, choose one. Hint: prefer the one that most closely aligns with the abstract meaning of the domain. A point that other commenters brought up is what to do in the case of user input. Lets assume it's unreasonable to expect the user to select a type explicitly. In this case I'd say there are actually three distinct types: int, string, unknown-currently-represented-as-a-string. This doesn't solve the problem of needing to select a type conversion, it just makes it more obvious that a type conversion must occur. This reminds me of Go's const numbers which are actually represented as abstract numbers with arbitrary precision during compilation and only get assigned a concrete value once its assigned to a variable that has a concrete type. This allows, for example, to have an expression using Pi which can be assigned to both float and double that utilizes each type's maximum precision.
- nybble41 5y ago> This reminds me of Go's const numbers which are actually represented as abstract numbers with arbitrary precision during compilation and only get assigned a concrete value once its assigned to a variable that has a concrete type. Haskell does something similar. Literal integers and decimal fractions are translated into expressions like "fromInteger (12345 :: Integer)" for "12345" or "fromRational (314159 % 100000 :: Ratio Integer)" for "3.14159" (where the % operator, defined in Data.Ratio, constructs a Ratio value from a numerator and denominator). The inputs have arbitrary precision, and the concrete type of the expression is resolved through the normal type unification process. IMHO the static type error, runtime type error, and always-false interpretations all have some merit, though naturally static typing without any implicit conversion has the best chance of detecting mistakes early on. The only one I would reject as obviously invalid is the one that says that "5"==5 is true.
- zeroimpl 5y agoFunny how they say SQL gets it right, but then shows an example which is the opposite of my experience. From PostgreSQL # select '5' = 5; ?column? -------- t (1 row) I believe this is standard SQL. Putting something in quotes just means it is a literal, doesn't mean it is a string. Of course if you explicitly cast it to a string, then you get an error. As in: select '5'::text = 5; ERROR: operator does not exist: text = integer LINE 1: select '5'::text = 5; ^ HINT: No operator matches the given name and argument types. You might need to add explicit type casts. I agree with the premise - SQL gets it right, but perhaps only in PostgreSQL?
- em500 5y ago> I agree with the premise - SQL gets it right, but perhaps only in PostgreSQL? I don't agree with the premise. Both MySQL[1] and MS SQL Server [2] do an implicit cast and then compare them as numbers. I don't know whether this is ANSI standard behavior though. [1] https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html [2] https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine?view=sql-server-ver15 https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-t...
- wydfre 5y agoBrendan Eich created the language in 10 days. Think about the billions of dollars and billions of man-hours that have spent related to a language not designed and slowly gained userbase, or scholarly, but a guy with a job. One guy. One guy in 10 days decided the fate of the internet. That's crazy. https://thenewstack.io/brendan-eich-on-creating-javascript-in-10-days-and-what-hed-do-differently-today/ https://thenewstack.io/brendan-eich-on-creating-javascript-i...
- tyingq 5y agoTo be fair, "5" == 5 is true for Awk, Perl, and Tcl. All of which were pretty popular at the time. Not discounting other implications of a 10 day design period :)
- int_19h 5y agoTcl isn't quite the same, since "5" and 5 are literally the same exact value in it, in all respects - not just equality. It's more of a problem in languages where, at the same time, 5+5==10 but "5"+"5"=="55".
- tyingq 5y agoAh yes, sure. Though "5"+"5" isn't "55" in Perl, Awk, or PHP either.
- brrrrrm 5y agoYou're referring to JavaScript whereas the post is about R
- wydfre 5y agoUh, you are right, I am an idiot. I just assumed that mistake was limited to one language... why did I have to be wrong about that.
- xscott 5y agoI wonder how different the world would be if he'd been allowed to use Scheme instead.
- diogenesjunior 5y agoAn integer cannot be inside a string. Simple as.
- deleted 5y ago[deleted]
- Kalanos 5y agofor what it's worth, `5` is not a valid json key, but `"5"` is.
- jareklupinski 5y ago'5' == 53 != 5 https://theasciicode.com.ar/ascii-printable-characters/number-five-ascii-code-53.html https://theasciicode.com.ar/ascii-printable-characters/numbe... have you all ripped down your ASCII posters already