Is a keyword argument a hash?

is a keyword argument a hash?

and when curly braces are skipped on a hash, how are you meant to know if it is a keyword argument or multiple keyword arguments, or a hash with curly braces omitted.

And assuming a keyword argument is not a hash, or that a keyword argument is a specific type of hash…

suppose you have

def abc x

abc fff:“f”


def jkl fff:

jkl fff:“f”

am I passing something different to abc than I am to jkl?

like am I passing a keyword parameter to jkl and a non-keyword-parameter to abc?

Absolutely. You are passing something different to methodabc than method jkl.
For simplicity consider the code:

def foo(x) x end

def bar(a:, b:) [a, b] end

p foo(a: 100, b: 200)
p bar a: 100, b: 200

# p bar a: 100    # ArgumentError

So, in foo, a and b are mandatory keywords. You can’t omit them. Also, you are passing the values of the hash to a and b. And the type has to be a hash, where the keys are symbols. So, following code after the above code raises an error:

p bar 'a' => 100, 'b' => 200

/tmp/p.rb:5:in `bar': wrong number of arguments (given 1, expected 0; required keywords: a, b) (ArgumentError)
	from /tmp/p.rb:12:in `<main>'

On the other hand foo takes one argument, be it a hash or an array or a string or anything.

It’s not much confusing. You define method with the def keyword or Kernel#define_method method. So you know which one is a method. Just to avoid confusion, use parentheses around the arguments, though that’s my personal opinion.
When you call the method, there are several ways, but you call it as a function in general (it’s possible because the top level methods are defined on the main object). If you still find method calls with hashes confusing, you can call them in various ways. For example:

define_method(:bar) { |a:, b:| [a, b] }

p bar({a: 100, b: 200})

# the send method is as fast as the above
p send(:bar, a: 100, b: 200)

# This is a bit slower than send, if you do it a million times
p method(:bar).(a: 100, b: 200)

# This even is slower than the method(...).call(...), and not recommended at all!
p Object.instance_method(:bar).bind(self).(a: 100, b: 200)

Hope this helps!