-
Notifications
You must be signed in to change notification settings - Fork 19
Description
Right now the internal representation of prod/sum types are structs, however these are not as efficiently matched in the BEAM as raw tuples are (especially since OTP 20 made matching on an atom in the first position of a tuple significantly faster). Have you thought about having the internal representation of sum/prod types be records (I.E. tagged tuples), so something like:
defmodule Light do
defsum do
defdata Red :: none()
defdata Yellow :: none()
defdata Green :: none()
defdata Custom do
red :: non_neg_integer()
green :: non_neg_integer()
blue :: non_neg_integer()
end
end
end
Would become basically:
:Red
:Yellow
:Green
{:Custom, red, green, blue}
Or maybe even (slightly slower and more GC work but barely):
{:Red}
{:Yellow}
{:Green}
{:Custom, red, green, blue}
Or perhaps an option on the defsum/defdata
to choose the internal representation?
A big bonus with this format is that you could then create guards, so you could have something like:
def myfunc(light) when Light.is(light), do: :blah
def is_specific_light(light) when Light.is(light, [Red, Yellow, Green]), do: true
def is_specific_light(light) when Light.is(light, Custom), do: false
And other such things? Currently it is not possible to do dynamic matching like that on a map/struct without controlling both the matcher and the guard (the best you can do is matching if it is a 'single' type, not one of a set of types, if you have the internal representation as a map/struct), since you can use elem/2
(and tuple_size/1
) in a guard to test (make sure to test non-tuple representations first then test via elem as later guards will not run if elem is used when it is not a tuple, or it does not matter if all internal representations are as a tuple. The BEAM is tuned for speed on matching tuples, not maps, and that includes what can be tested in guards as well. :-)