Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NamedTuple#merge(other : NamedTuple) #4688

Merged
merged 3 commits into from Sep 25, 2017

Conversation

Papierkorb
Copy link
Contributor

Hi,

Today in #crystal-lang a user required a possibility to merge two named tuples.
Their use-case was to call methods with named arguments from inside a RESTful API, while being able to easily set default values (or force other arguments to certain values).

Sample code

# Read arguments from user
args = NamedTuple(user: String, password: String).from(rest_arg_hash)

# Force the `server` argument to a value
call_args = args.merge(server: "auth.my-service.com")

# And easily call the actual method
authenticate(**call_args)

Using this, one can easily do dynamic invocation on methods, possibly backed by further user-defined macro magic ;)

Behaviour

Takes two named tuples (The other can be kw-args style, or a proper named tuple), and merges keys and values from both into a new named tuple. If both tuples define a value for the same key, the value from the other is kept.

Cya

def merge(**other : **U) forall U
{% begin %}
{
{% for k in T %} {% unless U.keys.includes?(k) %} "{{k}}": self[:"{{k}}"],{% end %} {% end %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use {{k.stringify}} and not "{{k}}". I think this is not safe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, please use {{k.symbolize}} and not :"{{k}}".

@need47
Copy link
Contributor

need47 commented Jul 7, 2017

I have been long waiting on this. Currently I have my own merge method. Glad to see it built-in stdlib.

Merges two named tuples into a new one.  If both tuples define a value
for the same key, the value of the *other* tuple is used.
@Papierkorb
Copy link
Contributor Author

Now using stringify and symbolize

@sdogruyol
Copy link
Member

I also had a similar case. Having a merge for NamedTuple would definitely help.

@asterite
Copy link
Member

Duplicate of #2634

I think I prefer the implementation of #2634

@asterite asterite marked this as a duplicate of #2634 Jul 14, 2017
@Papierkorb
Copy link
Contributor Author

#2634 blows up if both tuples have a value with the same key.

@emancu
Copy link

emancu commented Jul 15, 2017

@Papierkorb that was the main idea, I was trying to compose NamedTuples instead of merging them, so if you duplicate a key, it shouldn't compile.

In #2634 you can see a comment explaining why I discarded the merge function, however, I found really useful any implementation, so happy to see this merged :)

@Papierkorb
Copy link
Contributor Author

@emancu I totally see the worth in both methods, and I'd like to see both merged.

@straight-shoota
Copy link
Member

straight-shoota commented Jul 15, 2017

Actually I think there are three reasonable methods of combining two NamedTuples:

  • merge: Creates a new NamedTuple type with the union of all keys. For the same key, values from one overwrite those of the other. Different types for the same key should either fail or combine them to a union type (?). The inversion should return the same NamedTuple type with possibly different values (iff keys are intersected). Add NamedTuple#merge(other : NamedTuple) #4688
  • +: Creates a new NamedTuple type with the union of all keys. Fails if other and self share a key. The operation is commutative. Merge named tuples #2634
  • update: Creates a new instance of self's NamedTupe type with values of self updated with those of other. other's keys need to be a subset of self's keys. Inversion is only valid if the key sets are identical. The behavior is similar to merge but it ensures that no additional keys are added and preserves the types from self. Add NamedTuple#update(other : NamedTuple) to merge values but keep type #4727

For update there is no PR yet and I don't think it has been proposed before. I am not sure if the key and type safety provided over merge adds much because mismatching types will either result in type errors elsewhere or shouldn't be to much of a concern.

@Sija
Copy link
Contributor

Sija commented Jul 15, 2017

@straight-shoota If I understand correctly there's no PR for update because NamedTuple is meant to be immutable.

@straight-shoota
Copy link
Member

straight-shoota commented Jul 15, 2017

Of course it is. I'm sorry if this was misunderstanding, it would mean to create a new instance of the same NamedTuple type with updated values. I'll try to improve the wording on that.

@Sija
Copy link
Contributor

Sija commented Sep 22, 2017

@Papierkorb Would be sad to have this PR buried, so 🏓

@asterite
Copy link
Member

@Papierkorb Could you re-format the source files? It's only failing because of that.


# Returns a hash value based on this name tuple's size, keys and values.
#
# See also: `Object#hash`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant line.

@Papierkorb
Copy link
Contributor Author

@asterite Ah shoot, I'm away from home this week-end. Would it be okay if I do it on Monday?

@asterite
Copy link
Member

@Papierkorb Of course! Take your time :-)

@Papierkorb
Copy link
Contributor Author

Papierkorb commented Sep 25, 2017

Like this? Or should I fixup the original commit?

@RX14 RX14 added this to the Next milestone Sep 25, 2017
@RX14 RX14 merged commit ecd3368 into crystal-lang:master Sep 25, 2017
@emancu emancu mentioned this pull request Sep 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet