On Monday, August 29, 2016 at 2:26:41 PM UTC-6, Wiebe-Marten Wijnja wrote:
The idea is to be able to create application-specific comparisons between
data types, *where these comparisons make sense*.
Hmm, being able to compare disjoint types seems potentially painful and
most likely incurring a significant overhead compared to just doing it
manually... I'm guessing that is where the module explosion talked of
before came in to play. It sounds like needing to create a multi-method
dispatcher in Elixir, and if so the best you could get (without knowing all
types absolutely at compile-time) would be log(N) runtime, which is not too
bad...
You could potentially sneak in some tricks though. If you use something
like protocols (though something new, not protocol) to generate a call tree
in a single module, a single entrance function that matches based on both
of the types (properly ordered so the beam can efficiently match well)
would get it down to log(n). Hmm, although if you have a *lot* of
potential matches (and I mean a **LOT**) then you could dispatch into a map
and that 'might' be faster (though honestly I would not bet on it). This
would require a post-compile step like protocols do though (is there a
pattern to do those kind of things with elixir or are protocols just
'special'?). For normal macro's the best you could really get is to
manually specify everything in a single file in your base project, just
import the other modules that define matchers, and have a macro build up
the same call tree. Easy enough to do but does require the end-user to
import all other possible modules compare implementations into it so the
macro can build the call tree, which can be easy to forget something, but
good enough for an initial test implementation.
With that you would only have 1 module necessary (with an additional 1 for
each you import, but those could just be function calls onto some base
module for each type so that is effectively free). But the macro would
just generate something like:
```elixir
# Example structsdefmodule Bike do
defstruct gears: 5end
defmodule Car do
defstruct top_speed: 80end
defmodule Truck do
defstruct wheels: 4
def compare(%{wheels: wheels0}, %{wheels: wheels1}), do: Comparable.compareend
# An example of what a macro could generate given some information that
describes things:defmodule Comparable do
def compare(t, t), do: :eq # Could generalize this call to something like:
# def compare(%{__struct__: type}=t0, %{__struct__: type}=t1), do:
type.compare(t0, t1) # However that catches structs that do not support a
compare and has a speed overhead due to dynamic dispatch, so I would not
recommend it
def compare(%Bike{gears: gears0}, %Bike{gears: gears1}), do: compare(gears0,
gears1)
def compare(%Bike{}, %Car{}), do: :lt
def compare(%Bike{}, %Truck{}), do: :lt
def compare(%Car{top_speed: top_speed0}, %Car{top_speed: top_speed1}), do:
compare(top_speed0, top_speed1)
def compare(%Car{}, %Bike{}), do: :gt
def compare(%Car{}, %Truck{}), do: :lt
def compare(%Truck{wheels: wheels0}, %Truck{wheels: wheels1}), do:
compare(wheels0, wheels1)
def compare(%Truck{}, %Bike{}), do: :gt
def compare(%Truck{}, %Car{}), do: :gt
def compare(%{__struct__: _t0}, %{__struct__: _t1}, do: raise MatchError(blah)
def compare(t0, t1), do: if(t0<t1, then: :lt, else: if(t0>t1, do: :gt, else:
if(t0 == t1, do: :eq, else: raise MatchError(blah))))end
```
That should be quite easily optimizable by the beam and be quite efficient,
even with large match sets (log(n) specifically).
On Monday, August 29, 2016 at 2:58:15 PM UTC-6, José Valim wrote:
>
> Given the examples below, maybe it would be better to provide protocols
> for each of those cases. The protocol would convert those data types to an
> intermediate representation that would be easy to compare on.
This could indeed be faster, however you'd have to get everything to agree
on a single representation (a special tuple format perhaps? but then how
would that rank with other tuples?).
>
--
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/69a8649e-63b5-49dd-91b5-b9b97d6daef1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.