Idiom and/or efficiency and/or OCD

I wrote this code as a first pass (add a tuple to one of a list’s lists depending on it’s value).

def split({:C,x}, [cl, di, he, sp]), do: [slot({:C,x},cl),  di,  he,  sp]
def split({:D,x}, [cl, di, he, sp]), do: [cl,  slot({:D,x},di),  he,  sp]
def split({:H,x}, [cl, di, he, sp]), do: [cl,  di,  slot({:H,x},he),  sp]
def split({:S,x}, [cl, di, he, sp]), do: [cl,  di,  he,  slot({:S,x},  sp)]

then it “worried” me that I was deconstructing a value that I had to use, suspecting it was creating a new tuple … so I rewrote it to this

def split2(card, [cl,di,he,sp]) do
  case card do
    {:C,_} -> [slot(card, cl),  di,  he,  sp]
    {:D,_} -> [cl,  slot(card, di),  he, sp]
    {:H,_} -> [cl,  di,  slot(card, he), sp]
    {:S,_} -> [cl,  di,  he,  slot(card, sp)]
  end
end

Is one preferable to the other? Does it make a difference?

I’ll admit the impetus for this is a probably misunderstanding on my part about functional programming and “value re-use” (is that a term) a-la new_list = [ new_term | old_list] … not creating a new copy of old_list.

Having started as a C programmer, I find it hard not to worry about how stuff works/where data lives “under the hood” … I suspect the answer is “don’t think like that” … :slight_smile:

Jon

1 Like

I believe (but I’m not authoritative on this) that the underlying implementation will basically be the same. There’ll be a single match content to work out how to dispatch based upon {:C,x} and alternative friends. Only then will the list (the second param) be deconstructed.

Therefore I’d say readability, comprehensibility and maintainability come to the fore. In this case I prefer the second implementation since, for me, it rates higher on those three factors.

1 Like

Since OTP 19 IIRC the tuple construction is optimised away in your first example.

Nevertheless, let me show you a third way that is equivalent in its behaviour:

def split(card = {:C,x}, [cl, di, he, sp]), do: [slot(card, cl),  di,  he,  sp]
def split(card = {:D,x}, [cl, di, he, sp]), do: [cl,  slot(card, di),  he,  sp]
def split(card = {:H,x}, [cl, di, he, sp]), do: [cl,  di,  slot(card, he),  sp]
def split(card = {:S,x}, [cl, di, he, sp]), do: [cl,  di,  he,  slot(card, sp)]

I understand how you feel, but sometimes one has to trust in the runtime, as you often have to simply trust that your libstdc is implemented correctly.

2 Likes

Oh, I like that. I haven’t seen that construct before - but I’m new-ish - is that a specific thing, or sugar for a guard?

I do agree with Kip that somehow the second version is clearer … but the first version is so “magic-y”. :smile:

Jon

1 Like

No, its a regular match. actually I realize now, that it will create warnings because of the unused xs, so one had to replace them with _,

2 Likes