proposal: Shorthand syntax to access structs keys values with compile-time checks

62 views
Skip to first unread message

Ulisses De Almeida

unread,
Feb 22, 2020, 3:22:20 PM2/22/20
to elixir-l...@googlegroups.com
Good evening, morning, afternoon!

I was wondering with my team what is the best way of acessing keys from structs, and we have the dynamic way. That's is something like:

def create_order!(item, user) do
 
Repo.insert!(%Order{
   
user_id: user.id,
   
user_email: user.email,
   
user_shipping_address_id: user.user_shipping_address_id,
   
total_price: item.price,
   
total_weight: item.weight,
   
quantity: 1
 
})
end

This dynamic way is very short and direct to the point. However, if there's any typo on the key, if we don't have any unit test, it will show up during the runtime.

Elixir then, provide us the pattern matching way:

def create_order!(
     
%Item{
       
price: item_price,
       
weight: item_weight
     
},
     
%User{
       
id: user_id,
       
email: user_email,
       
shipping_address_id: user_shipping_address_id
     
}
   
) do
 
Repo.insert!(%Order{
   
user_id: user_id,
   
user_email: user_email,
   
user_shipping_address_id: user_shipping_address_id,
   
total_price: item_price,
   
total_weight: item_weight,
   
quantity: 1
 
})
end

We split up in two steps, one to bind the key value to a variable, then another step to build the new struct. This extra step make the code more verbose generating 2*n lines where `n` is the number of attributes you want to assign.

We're discussing how we could make the code shorter and straight to the point like the dynamic version, we thought in something like creating functions to get values from the keys. Something like:


def create_order!(item, user) do
 
Repo.insert!(%Order{
   
user_id: User.id(user),
   
user_email: User.email(user),
   
user_shipping_address_id: User.shipping_address_id(user),
   
total_price: Item.price(item),
   
total_weight: Item.weight(item),
   
quantity: 1
 
})
end

Using functions like this, we have compile time checks that we didn't make any typo and also is shorter and straightforward like the dynamic version.
The downsinde is creating functions like this, it's a little bit boring and repetitive. I was thinking if there's any space for a shorthad syntax.

Today we have a shorthand syntax to update key values like this:

%User{user | email: "aaaa"}

I wonder if we can have similar syntax to get a value from a key. Suggestions:

%User{user | :email}
%User{user |> :email}
%User{user -> :email}

Then we could write:

def create_order!(item, user) do
 
Repo.insert!(%Order{
   
user_id:
%User{user -> :id},
   
user_email:
%User{user -> :email},
   
user_shipping_address_id:
%User{user -> :user_shipping_address_id},
   
total_price: %Item{item -> :price},
   
total_weight: %Item{item -> :weight},
   
quantity: 1
 
})
end



What do you folks think? Does it make sense?

--

Wojtek Mach

unread,
Feb 22, 2020, 4:31:08 PM2/22/20
to elixir-l...@googlegroups.com
When we do:

    def foo(%User{} = user) do
      user.bad_field
    end

The compiler should have all the information it needs to catch invalid fields. (At least until the variable is re-bound but ideally even then.) So I believe there is no need to introduce new syntax!

--
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 elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAFvtSL4bByyHW7EOQrZ1%2B%3D5%2BredchXL0wNS1U08rVV-BuFwwZg%40mail.gmail.com.

Ulisses De Almeida

unread,
Feb 23, 2020, 3:16:34 AM2/23/20
to elixir-l...@googlegroups.com
It's true. I assumed this check wasn't happening because of some limitation of the syntax. But, like you said, it does have all the information.

I wonder why it's not happening now. Was it intentional? 

I would like to introduce this check if there's no drawback . However, I don't know where to start. If you folks could give me some orientation where I should start to look at it.

José Valim

unread,
Feb 23, 2020, 4:08:48 AM2/23/20
to elixir-l...@googlegroups.com
We are not checking right now the plan is to check in the future. :) Possibly by 1.12 or 1.13.

Ulisses De Almeida

unread,
Feb 23, 2020, 4:26:05 AM2/23/20
to elixir-l...@googlegroups.com
Amazing ♥️♥️♥️💜💜💚💙🤎💛

Reply all
Reply to author
Forward
0 new messages