> Also, the current proposal for coerce doesn't handle coercing from struct 
to struct. If it does, it requires both sides implement the coercion and 
having an intermediate representation is almost always better.

I am not really following your reasoning here. It seems like you state that 
not being able to handle struct<->struct coercions is a flaw of the 
proposal, but then you go on saying that having an intermediate 
representation is always better, meaning that coercion in these cases is 
not relevant.

> By integrating into the language, I mean in a way that it would yield 
large benefits only if made part of the language. The proposed solution and 
Decimal yield almost no benefits if part of Elixir compared to as a 
package, besides reachability.

The main reason why I believe that this should be integrated into the 
language is for the same reason that the (Naive)(Date)(Time)-structs were 
made part of the language: Consistency and therefore Interoptability 
between libraries.
A secondary but nearly as important reason would be that newcomers into the 
language quickly learn that using the standard comparison operators is not 
the way to go on custom data structures.

I am not sure what the process should be when implementing this outside of 
the core language: 
Should there be one library containing the protocol, and then for all 
libraries that happen to have comparison functionality another library that 
implements the protocol? (And thén also the libraries that build on top of 
the Comparable interface?)

Per the Dependency Inversion Principle, it would make more sense if 
Decimal, Timex, Ratio etc. would implement the Comparable protocol 
directly. However, the chance of this happening if 'Comparable' is just 
another Elixir library written by just another person is very low, because 
nothing is stopping any other person to write 'Comparable2' that works in a 
slightly different way and request from the authors to implement *that* one. 
A separate library lacks the authority required to standardize the 
comparison interface.

Ergo, this would mean that there would be a `comparable` library, and the 
'compatibility-layer' libraries: `comparable_timex`, `comparable_decimal`, 
`comparable_ratio`, etc... And then finally libraries like `priority_queue` 
that are built on top of `comparable`. However, using these libraries that 
are built on top of 
`comparable` is not so nice, because the responsibility of making sure that 
the proper 'compatibility-layer' is loaded as a dependency shifts to the 
end user.

For example: if I then am building an application and need a priority 
queue, I'll need the `priority_queue` library, the `decimal` library and 
not forget to add the `comparable_decimal` library: 
Even though this is an implementation detail of PriorityQueue, it cannot 
have `comparable_decimal` as an dependency because that would not make 
sense for all the projects that do not use Decimal. 

There are many algorithms and data structures that would want to work with 
a Logical Ordering (rather than the Erlang Term Ordering). Including but 
not limited to:

- Sorting algorithms
- Searching algorithms
- Sets
- Multisets
- Maps
- Multimaps
- Trees (of which there are of course many shapes and kinds)
- Graphs and their related structures.
- Pathfinding algorithms.
- Permutation manipulation algorithms.

Working with partially and totally ordered data structures is something 
very universal. I know of at least:
- Haskell (the Ord typeclass), 
- Rust (the Ord trait), 
- Java (The Comparable interface), 
- .NET (the IComparable interface),
- Ruby (the spaceship <=> operator and `coerce`), 
- PHP (the spaceship <=> operator), 
- Python (functools.total_ordering() and __cmp__(a,b) and friends) 
- and C++ (the Comparable Concept).

All of them provide a built-in standardized way to implement custom logical 
comparisons for your data types, and because of this allow generic 
algorithms and data structures to be built on top.

I hope that I have proven with above arguments the importance of including 
standardized comparison functionality in the core language, rather than in 
a peripheral library which lacks the authority that is required for 
standardization.


~Wiebe-Marten/Qqwy


On Saturday, June 17, 2017 at 12:29:48 AM UTC+2, José Valim wrote:
>
> By integrating into the language, I mean in a way that it would yield 
> large benefits only if made part of the language. The proposed solution and 
> Decimal yield almost no benefits if part of Elixir compared to as a 
> package, besides reachability.
>
> Also, the current proposal for coerce doesn't handle coercing from struct 
> to struct. If it does, it requires both sides implement the coercion and 
> having an intermediate representation is almost always better.
>
> If the goal is to standardize return types, then I think the best is to 
> actually start using them in Elixir itself. We have already started with 
> the calendar types, so others will be able to follow accordingly.
>
>
>
>
> On Sat, Jun 17, 2017 at 00:16 Wiebe-Marten Wijnja <[email protected] 
> <javascript:>> wrote:
>
>> Hello Jose,
>>
>> I completely understand where you are coming from. 
>>
>> The main reason to add this to the core language is to standardize the 
>> return format of comparison functions. I believe this to be a very 
>> important idea.
>> *Upcasting* as in the case of Decimals can be supported using the 
>> coercion-mechanism explained earlier (and already implemented in the 
>> Numbers library: https://github.com/Qqwy/elixir_number/).
>> *Downcasting* as in the case of the (Naive)(Date)(Time) modules on the 
>> other hand is something that should happen explicitly in my opionion. 
>> Therefore, this feels like a feature that should not be supported on a 
>> protocol. Instead, I'd propose to keep the (Naive)(Date)(Tiime).compare 
>> functions for that purpose.
>>
>>
>> Again, the main important reason is to standardize the return type of the 
>> comparison functions.
>> If this is standardized, it becomes possible to write libraries that can 
>> build on top of it. Some ideas:
>> - An ExUnit add-on library that adds assertions like `assert_smaller`, 
>> `assert_not_equal` etc.
>> - Alternative container data structures that provide functionality based 
>> on the logical ordering of data structures (rather than the Erlang Term 
>> Ordering), such as priority queues that do not care if the priority is 
>> provided as a Decimal or a DateTime.
>>
>> Right now, building those kinds of things is plain impossible, because 
>> you would need to handle the five different types of return values of 
>> `SomeModule.compare/2`. 
>> Another benefit I see is that programmers would not need to guess what 
>> kind of return value a comparison function has. 
>> Yesterday I spent half an hour debugging why a list of timestamps was not 
>> split at the correct location. Turns out I was doing `Timex.compare == :lt` 
>> whereas it should have been `Timex.compare == -1`, which is the kind of 
>> implicit implementation behaviour I'd like to not need to think about all 
>> the time as a programmer.
>>
>>
>> I do not feel that the comparison with Decimal makes a lot of sense, 
>> since this proposal is a lot smaller. Also, `compare/2` and 
>> `Comparable.compare/2` will integrate in the language quite a lot, since 
>> they will work for built-in types, expecting the two operands to be of the 
>> same type( both numbers, both lists, both binaries, both the same kind of 
>> struct, etc.).
>>
>> Please standardize the way comparisons are made in the language. It is a 
>> very small addition but it will ensure that libraries are consistent in 
>> their APIs, allowing new libraries to flourish on top.
>>
>> ~Wiebe-Marten/Qqwy
>>
>> On Friday, June 16, 2017 at 11:23:26 PM UTC+2, José Valim wrote:
>>>
>>> Hi  Wiebe-Marten Wijnja,
>>>
>>> Thanks for the well-written proposal.
>>>
>>> I am afraid my opinion has not changed much from the first time around.
>>> The proposed solution would not support the "downcasting" done in 
>>> `Date.compare`. `Decimal` may also want to perform casting as well.
>>> And while I understand why it cannot support that and I would take the 
>>> same decision as you, it makes it less appealing as we would still need a 
>>> custom function in those cases.
>>> And it may also be that those are actually better solved with a specific 
>>> compare protocol, such as RataDieCompare or NumberCompare and not a general 
>>> purpose one.
>>>
>>> So I believe those protocols should be developed as a separate package 
>>> and not included in Elixir.
>>> I do understand the benefits of including it in Elixir itself but to me 
>>> the conceptual cost of the new abstraction / mechanism outweighs the gains 
>>> in this case.
>>>
>>> I believe I have mentioned in the past the Decimal library is currently 
>>> on the same situation.
>>> It is very useful but, unless it is meant to integrate into the language 
>>> in a more meaningful way, it will do just fine as a separate package.
>>>
>>> -- 
>
>
> *José Valim*
> www.plataformatec.com.br
> Skype: jv.ptec
> Founder and Director of R&D
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/dac1a940-9406-4e45-9c40-1aca76ddaea1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to