I have been thinking longer about this.

I think that the across-type implementation is overkill; I have a lot of 
trouble to come up with cases where this would be useful: Cases that I can 
think of can readily be solved by wrapping the inner structure in a 
containing struct, which is obviously more clear/explicit than providing a 
two-typed frankenprotocol.


I have been working on Numbers, which is basically dispatches arithmetic 
operations to any structs that implements its standardized Numeric 
behaviour. In this case, this means that functions/modules/structs can be 
written that wrap *any* kind of thing that implements the behaviour, which 
means that e.g. my Tensor library allows addition/multiplication to 
performed regardless of if the contents of the vectors/matrices/tensors are 
`Integer`s, `Float`s, `Decimal`s, `Ratio`nals or even `ComplexNum`bers.

I think that such a *standardized* way constructing something still is very 
important in the core language, because a standardized API means that 
modules consuming the API can use any modules(/data types) that are 
exposing the API.

I now envision the following, much simpler and less 'new language 
feature'-heavy than my original proposal:

---------------------

There is a *normal* protocol called Comparable, exposing two functions that 
can be overridden:

   - *compare(a, b)* compares the two structs `a` and `b` of the same type. 
   This function should return `:lt`, `:gt`, or `:eq` (keeping with the 
   specification that DateTime.compare and Time.compare already follow). If 
   there is no sensible way to compare the two types, a 
   *Comparable.CannotCompareError* should be raised, with a describing 
   error message. The *Any* implementation always raises this error.
   - *coerce(some_builtin_value)*.  Can optionally(!) be implemented to 
   allow certain standard data types (e.g. numbers, or strings) to be 
   automatically converted to the type of the thing we want to compare it 
   with, to allow shorter notation for things like `compare(Decimal.new(2), 
   3)`. The *Any* implementation always raises 
   *Comparable.CannotCompareError*.

There is a new function in the Kernel function *Kernel.compare(a, b)* has 
the following variants:

# struct <=> struct
Kernel.compare(a = %someStruct{}, b = %someStruct{}), do: Comparable.compare
(a, b)
# struct <=> differentStruct
Kernel.compare(a = %someStruct{}, b = %someDifferentStruct{}), do: raise 
Comparable.CannotCompareError, message: "Cannot compare #{inspect(a)} with 
#{inspect(b)}."
# struct <=> builtin
Kernel.compare(a = %someStruct{}, b), do: Comparable.compare(a, Comparable.
coerce(b))
# builtin <=> struct
Kernel.compare(a, b = %someStruct{}), do: Comparable.compare(Comparable.
coerce(a), b)
# builtin <=> builtin, use Erlang's built-in term ordering.
Kernel.compare(a, b) when a == b, do: :eq
Kernel.compare(a, b) when a < b, do: :lt
Kernel.compare(a, b), do: :gt








-- 
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/a7e59ba9-699b-42db-a81f-cbda00179fc8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to