Do note, in my example the lines like:
def compare(%Bike{gears: gears0}, %Bike{gears: gears1}), do: compare(gears0,
gears1)
The `compare(gears0, gears1)` part is writer-defined, it could call into a
module function, it could do an inline compare like the above is doing,
whatever is appropriate for the type.
On Monday, August 29, 2016 at 3:04:17 PM UTC-6, OvermindDL1 wrote:
>
> 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/d1cc865e-11d6-4d56-bead-63a0f3dea3c4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.