Closed
Description
@StephenVavasis has pointed out some rather confusing behavior of the in
operator, including:
julia> VERSION
v"0.3.0-rc2+12"
julia> x = IntSet([3,5])
IntSet([3, 5])
julia> in(3,x)
true
julia> in(x,3)
false
julia> in("abc",19)
false
julia> in(19,"abc")
false
Worse still is this:
julia> 97 in "abc"
true
This issue is to discuss what, if anything, we can do to reduce some of this confusion.
Activity
JeffBezanson commentedon Aug 7, 2014
x in y
is pretty simple: doesx
== any element iterated byy
.The issue is not specific to
in
;97 == 'a'
is true.I do think it would be good to make
Char
not an integer type. In theory having numbers not be iterable might be ok, but I think it will be very annoying in practice.see also #5844
StephenVavasis commentedon Aug 8, 2014
So I guess the problem is not specifically with `in' but with ==. I raised the issue that apparently meaningless uses of 'in' do not generate errors because I made silly blunder with 'in' in my project that did not generate an error message. For a similar reason (ease of debugging) the following uses of == should also generate errors, no?
julia> [3,4,5] == ["x","y"]
false
julia> IntSet() == ["a"=>7]
false
julia> 9 == Int64
false
julia>
JeffBezanson commentedon Aug 8, 2014
Our == is total, defined on all pairs of values. I find this convenient,
and I think it is quite difficult to decide exactly which cases to exclude.
On Aug 7, 2014 8:15 PM, "StephenVavasis" notifications@github.com wrote:
StephenVavasis commentedon Aug 8, 2014
Jeff,
I guess it's OK to make == total, but there also ought to be a restricted
version of == that requires the two operands to have the same type in
order to catch programmer blunders. I would guess that it is rare among
scientific codes to have a need for == with unequal types. Is there such a
restricted version available in Julia? (And is there a similarly
restricted version of 'in'?)
-- Steve
On Thu, 7 Aug 2014, Jeff Bezanson wrote:
timholy commentedon Aug 8, 2014
Three
=
:jey commentedon Aug 8, 2014
However that is for object identity, not equality. I.e. (zeros(3) ===
zeros(3)) is false
On Thursday, August 7, 2014, Tim Holy notifications@github.com wrote:
tkelman commentedon Aug 8, 2014
One option is you can pick your favorite unicode equality-resembling symbol from this list
julia/src/julia-parser.scm
Line 13 in 31eb8d4
==
but open for user definitions, and make that operator error on inputs of different types.StephenVavasis commentedon Aug 8, 2014
Earlier I wrote that it seems OK for == to work for all possible operands, but now I changed my mind. The (small) increase in expressive power does not offset the potential for enabling programmer blunders. One important mission of a programming language is to help prevent the programmer from shooting himself/herself in the foot, and in this case Julia needlessly fails to close a loophole.
About 25 years ago when I was a CS prof at Cornell, the issue came up (again) whether to switch our introductory programming course to C, and our faculty unanimously rejected the idea (again) for many reasons. One of the reasons was that we did not savor the possibility of undergrads lined up outside the TA office for help with their assignments because they wrote
"if (x=0)" in their homework (instead of "if (x==0)") . The same rationale still applies to Julia 25 years later; it should not be possible to compile a program with in(x,3) where x is an IntSet, nor a program with x==t, where x is an Int and t is a Dict.
nalimilan commentedon Aug 8, 2014
It seems it would be better to add restrictions to
in
than to==
. For example,in
could require that the second argument is a collection rather than a scalar.I also agree that
Char
shouldn't be considered as an integer type. There'sUint8
for this use case.JeffBezanson commentedon Aug 8, 2014
I find the case for restricting
in
much more convincing than for==
.With
==
, people will write code to look for a certain value, likex == 0
. In a very generic context, you might not know whatx
could be. This applies even more for sentinel values, e.g.x == :none
. It would be too much of a gotcha to require also checking that the comparison will be valid, e.g.if isa(x,Symbol) && x == :none
. Also imagine aDict{Any,Any}
, where arbitrary keys need to be compared.In other words, it would be too difficult to get back the current behavior. You would need something like
if comparable(x,y) && x==y
, but it's not clear how to writecomparable
. In contrast, it is currently fairly easy to add extra restrictions if you want.ckhroulev commentedon Aug 9, 2014
Another (unrelated) issue
in()
seems to have is thatin(x, s::Set)
callshaskey
to check equality (see set.jl:16), ignoring user-defined==
andisequal
.Please let me know what you think about this, and feel free to move this elsewhere if appropriate.
Here's an example:
Now, compare
and
I did not expect this.
This also breaks
unique
(tryunique(edges)
), which usesin(x, s::Set)
internally.In this particular case a simple workaround is to define the (inner) constructor
and use default
==
andisequal
, but a solution like this one may not be possible in for other user-defined types. (This reminds me of a discussion of the relationship between "a == b" and "hash(a) == hash(b)".)PS: As far as I can tell recent code in the
master
branch should show the same behavior.JeffBezanson commentedon Aug 9, 2014
You also need to implement
hash
for sets and dicts to work properly with user-defined==
.jey commentedon Aug 9, 2014
Hm, perhaps
Set
should be calledHashSet
to preserve the mathematical meaning of "Set
"? Overall, the mathy types aren't fully internally consistent, IMO.89 remaining items