[swift-evolution] Proposals: (1) Forbidding custom `==` for value types, (2) `dispatch` keyword, (3) `default`-result for methods with `Self`, and (4) Poor-Mans-Existentials

Johannes Neubauer neubauer at kingsware.de
Tue Jul 19 01:51:19 CDT 2016


> Am 19.07.2016 um 06:29 schrieb Félix Cloutier <felixcca at yahoo.ca>:
> 
>>> 
>>>> 1. You cannot say something is unequal although the system says it is equal
>>> 
>>> That doesn't make me feel much safer. Comparison returned false when it should have returned true?
>> 
>> Yes you just may have a condition inverted e.g.. You could even have a compiler flag, where you remove the short-circuit and throw an error, if you have a false-negative. This would ease finding such issues (easier than just not having this feature)
> 
> This minor enhancement could most likely be obtained by just having a default ==, which is a project that I can get behind.

Structs do not have a common ancestor, this is why swift uses existential containers, in order to create polymorphic behavior for protocol types with value type implementations. So implementing such a default == would bring changes to swift either. But I didn’t bring this idea in the first place to have some more convenience. I am sure (and literature as well as my experience as a developer and project lead in many industrial projects proves me right), that implementing equality is a major source of errors in software development and I think that you underestimate this issue. This issues are really hard to track down. It is always better to implement a custom protocol for custom equality semantics, so that it doesn’t interfere with the expectations of the standard library and the many libraries to come, that will depend on the equals-contract.

Swift has the chance, not to make the same mistakes that other languages did before. But perhaps I just have to wait until Swift 3 has finished and repost the proposal, so that the core team has time to revisit it and we can start a fruitful discussion. Because right now I have the feeling that we are just spinning although I am 100% confident that this proposal (or at least a modified variant) is beneficial for swift.

> Also, what about C structures with character arrays? They get translated as tuples of CChar (if that's what they're still called now, didn't really keep track). The two are equal as soon as you hit a null terminator, but memberwise comparison doesn't know that.

They can have its own standard implementation. There is a lot of translation going on between Objective C <-> Swift as well as C <-> Swift (e.g., some constants are automatically coerced into enums).

>> Invisible behavior is everywhere: Automatic Reference Counting, Existential Containers, Virtual Functions, …
>> 
>> Swift is a high-level language, so it’s main appeal is invisible behavior, but I would call it *rich semantics* or something like that.
> 
> There is an actual demand for these. With ARC, I don't need to think about memory management (too much).

You have to, as soon as you have cyclic structures (weak, unowned). It is a tradeoff between performance (ARC) and convenience (garbage collection).

Analogously, Having a better corset for equality helps me not to think so much about doing this implementation right.

> Virtual functions let me implement OO design, which allows a ton of developers to leverage experience. With forced memberwise comparisons, I can trade easily debuggable problems for surprising behavior.

With my proposal you wouldn’t make it harder to find these issues it makes it easier. As I told before, you could have an instrumentation/error handling, that (in debug mode) does both checks default and custom implementation (so no short-circuit) and inform you about false-negatives automatically.

> Also keep in mind that most of these things are criticized to some degree. ARC is a common enough source of bugs that Apple has a relatively large investment into tools specially made to debug them.

This is due to the tension between the goal „safety“ and „performance“. Perhaps swift switches to garbage collection in the future. Or they decide to use garbage collection on fast devices as well as ARC on slow devices. Who knows.

> OO also has a ton of detractors.

Yes, because it is not restrictive enough in it’s current implementation. This is why I add these proposals. But there is not just black and white. Languages like Haskell are not that widely adopted, because a pure functional approach has its own downsides. Try to implement something like SpriteKit with Haskell.

>> It is like a virtual method, but for arbitrary parameters, so you need some kind of V-table for that and a lookup, that can be done in constant time. It is something, that I wouldn’t add by default. It is something that you may add to a method explicitly via a keyword (instead of implementing the dynamic dispatch by hand, by calling an `equals:other` method on the left-hand-side and then doing an if-cascade for rhs for example; which is error-prone). So you may use it wisely only, where necessary (and the internal implementation of swift will be much faster, than the manual variant). The XTend language has such a feature.
> 
> I didn't understand what you meant with dispatch. Now, my understanding is that it would be used to implement virtual dispatch over multiple parameters (instead of just `self`).

Yes and no. Operators (like ==) do not have `self`, this is a major issue IMO, since even the left-hand-side is not dispatched. Operators (and global functions) are non-virtual.

> What? You want to force every equality check to start with a memberwise comparison of *everything*.

I just proposed these two standard implementations executed before any custom implementation (no recursion or anything alike):

1. a `memcmp` for value types (not recursing through referenced types or anything) and
2. a === check for reference types (just comparing one address)

>>> Please realize that this is an absolutely radical change. Swift currently has little to no invisible behavior, and currently lets you implement equality any way that you like. In my book, radical changes should be considered with extreme skepticism, and should have an extremely compelling case behind them.
>> 
>> First off, I don’t think, that the changes are that radical and second this example gives a small insight how bad you can implement equality in swift:
> 
> None of it is hard enough to debug to justify a performance hit. Just because you're able to misuse a feature is not an argument that this feature shouldn't be available, especially if you can only half-solve the problem.

You cannot solve the `null` problem or the fragile base class problem completely either, but still swift has:

1. no abstract classes and no abstract methods
2. optionals
3. 2-phase initialization

to narrow the problem space.

> Why can't you be content with a default implementation? People all over are saying "don't touch my code", there's a very easy way to not touch anyone's code, but it's like you really want to.

As mentioned above AFAIK this would introduce a change to swift either, since structs don’t have a common ancestor (in terms of „inheritance“) **and** this would just be a convenience feature and not help to reduce really hard to trace bugs.

These features aren’t only for the master-of-the-blaster programmer. In a normal project you have differently skilled programmers and a type system should help even the average skilled one.

All the best
Johannes

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 496 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160719/d1d38c44/attachment.sig>


More information about the swift-evolution mailing list