-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deprecate ==
for refs and procs
#224
Comments
I agree that there has to be done something about this. Adding new operators for different kinds of equality is common practice in scripting languages (though mostly as a fixup for bad language design think of Maybe new operators for value comparison could be added? Another idea would be for example for hash tables, to keep the default behaviour (hash and compare the pointer not the value it stands for), but add some kind of wrapper type, like this: type CompareDeref[T: ref] = object
reference: T
converter getRef[T](refVal: CompareDeref[T]) = refVal.reference
proc `==`[T](a, b: CompareDeref[T]) =
a[] == b[]
... These are just some ideas I have on this topic. Though the utility of ref values as keys is debatable considering the dangers (making the datastructure invalid by changing the value externally...). |
==
for refs and closures==
for refs and procs
Two |
|
I think that wouldn't be a very good idea, since it breaks consistency. (in an alternative reality where programming languages were german, das gleiche und das selbe would solve this problem quite well) |
|
I usually overload proc `==`(self, other:MyRefT): bool =
if self.isNil: other.isNil
elif other.isNil: false
else: self[] == other[] not everyone may want this, so deprecating is fine. |
Type bound operations are already supported for
that would be a large breaking change;
Furthermore, that'd be dangerous because of converters, or concepts (which interchange
that RFC is not needed for that; see instead #229 which instead deprecates implicit conversion
proposal
there are many differences with semantic equality, as shown below: # in std/bitequals.nim and re-exported from std/bitops
when true:
proc bitEqualsUntyped[A, B](a: A, b: B): bool =
const na = A.sizeof
const nb = B.sizeof
return na == nb and equalMem(a.unsafeAddr, b.unsafeAddr, na)
template bitEquals[T](a, b: T): bool = bitEqualsUntyped(a, b)
doAssert 0.0 == -0.0
doAssert not bitEquals(0.0, -0.0)
doAssert bitEquals(-0.0, -0.0)
doAssert bitEqualsUntyped(-0.0, cast[uint64](-0.0))
var a = 0/0 # nan
doAssert a != a
doAssert bitEquals(a, a)
block:
var a: cstring = "abc"
var b1 = "abc"
var b = b1.cstring
doAssert a == b
doAssert not bitEquals(a, b) (see also nim-lang/Nim#8436 for additional motivation + use cases for |
Correct,
I consider |
there's another situation where the current |
I am repeating @Skrylar but:
What is wrong with that? I think the change is bad for 2 reasons:
Furthermore The issue is not that The solution is to improve knowledge, i.e. what is the difference between a value and a reference |
There is little connection between "I want no copy" and "I want to compare identities and the machine address is fine as the identity". You can opt into comparisons but why should there be an error-prone default that is inconsistent with |
Now you said the forbidden People can have their custom I don't know of any other language with types with reference semantics where
Also refs are often used for unique resources and you don't hash a socket or a database connection, you would need to write a custom There are good reasons to depart from status quo in language design but for this specific case, consistency between hash and comparison doesn't seem enough for me. If anything it's even worse than not being able to print |
Well that's why Nim has it but copying bad design is not good design.
And again, I see
No and how to do it is covered in my RFC. |
I don't see the inconsistency with
and btw that's what other languages do too (eg D, C++); custom eg: https://dlang.org/spec/hash-map.html
(ditto with java equasl vs hashCode, or C++) import tables, hashes
proc hash(a: ref|ptr|pointer): Hash = cast[Hash](a)
type Foo = ref object
id: int
type Bar = ref object
id: int
proc `==`(a, b: Bar): bool = a.id == b.id
proc hash(a: Bar): Hash = a.id
block: # default case: identity = address
var t: Table[Foo, int]
let a = Foo(id: 3)
let b = Foo(id: 3)
t[a] = a.id
doAssert a in t
doAssert b notin t
block: # special case: identity = id
var t: Table[Bar, int]
let a = Bar(id: 3)
let b = Bar(id: 3)
t[a] = a.id
doAssert a in t
doAssert b in t
i see note
summarywe'd just have:
|
@timotheecour I agree with your points, though I don't see the need for |
I consider this RFC as rejected and I'm waiting for more type-bound operators as the alternative solution. |
I would not mind I live in the profiler anyways and would stop performance issues quickly, people that don't don't live in the profile don't care as much about performance. I think its a win-win for both groups. |
|
Wouldn't the ideal case be when the compiler could detect that the copied value weren't changed so instead of copy it pass it as reference? |
Yeah, yeah, yeah... |
Equality is hard and sometimes there is not one kind of equality, but multiple. The Nim compiler is a good example of this, whenever you write
a == b
wherea, b: PNode
it's likely a bug. Instead some tree structure comparsion should be used.Motivation
Problem: .error doesn't work that well
The default ref equality is error prone and even
.error
doesn't work all that well:Problem:
==
for refs is inconsistent withhash
Because the standard library knows that equality is hard, no
hash
forref T
is provided inhashes.nim
, that's good but it's inconsistent with==
.Problem: Function merging is less effective
Generic instantiations can often lead to the same binary code (for example
fac[int]
andfac[BiggestInt]
can be identical) but the optimizer cannot blindly merge the identical functions if the language spec requires thatf != g
forproc f; proc g
. At the same time, hardly any valid usages for function equality are known; it suffices ifisNil(f)
works.Proposal: Deprecate
==
forref
and procsInstead of opt-out you have to opt-in in order to get reference equality for
refs
. There is a new operation,system.equalRefs
for the pointer-like reference equality. Then it's particularly easy toimplement a custom
==
operator:Alternatives considered
Conceptually equality is tied to a type much like assignments and destructors. If we bind equality to the type internally, the
.error
solution starts to work too. But then the same applies tohash
and$
and we need to support type bound operations properly. So it would add a new concept to Nim or at least expand an existing concept. Removing a very questionable default seems to be the better solution. (But I personally want type bound operations too...)The text was updated successfully, but these errors were encountered: