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.