Abstraction of shared keyword arguments

This is just a brain dump. Maybe someone has a comment on this.

I’ve been wondering about the scenario where a couple of methods receive the same (or very similar) keyword arguments.
And example for that would be methods that share the same base functionality but with different parameter types (e.g. one overload for String, one for Regex). Maybe they even delegate to each other.

If they accept the same keyword arguments, it would be nice if those could be declared only once instead of repeating them all over again for every single def.

def foo1(*, bar : String, baz : Int32 = 42)
  foo2(bar: bar, baz: baz)
end

def foo2(*, bar : String, baz : Int32 = 42)
  {bar: bar, baz: baz}
end
  

foo1 bar: "abc", baz: 1 # => {bar: "abc", baz: 1}
foo1 bar: "abc" # => {bar: "abc", baz: 42}

To some extend, a NamedTuple type can do this:

alias FooOptions = NamedTuple(bar: String, baz: Int32)

def foo1(**options : **FooOptions)
  foo2(**options)
end

def foo2(**options : **FooOptions)
  options
end
  

foo1 bar: "abc", baz: 1 # => {bar: "abc", baz: 1}

It’s also nice for delegation that all keyword args are combined in a single variable which can be easily passed on without repetition.

But in a NamedTuple type, all keys and values are required. It’s not possible to specify a default value.
But this is very common for named arguments. Most of them have default values and can be omitted unless you want to explicitly override the default.

Maybe we should be able to define default values for a NamedTuple type? :person_shrugging:

1 Like

related post

1 Like

Not sure about the implications for Crystal’s type system, but TypeScript has a Partial type for cases like that: Documentation - Utility Types