When can a method be called with fewer arguments than exist in the parameter list for the method?

I'm a bit confused about Javascript undefined & null.

null generally behaves similarly to other scripting languages' concepts of the out-of-band ‘null’, ‘nil’ or ‘None’ objects.

undefined, on the other hand, is a weird JavaScript quirk. It's a singleton object that represents out-of-band values, essentially a second similar-but-different null. It comes up:

  1. When you call a function with fewer arguments than the arguments list in the function statement lists, the unpassed arguments are set to undefined. You can test for that with eg.:

    function dosomething(arg1, arg2) { if (arg2===undefined) arg2= DEFAULT_VALUE_FOR_ARG2; ... }

    With this method you can't tell the difference between dosomething(1) and dosomething(1, undefined); arg2 will be the same value in both. If you need to tell the difference you can look at arguments.length, but doing optional arguments like that isn't generally very readable.

  2. When a function has no return value;, it returns undefined. There's generally no need to use such a return result.

  3. When you declare a variable by having a var a statement in a block, but haven't yet assigned a value to it, it is undefined. Again, you shouldn't really ever need to rely on that.

  4. The spooky typeof operator returns 'undefined' when its operand is a simple variable that does not exist, instead of throwing an error as would normally happen if you tried to refer to it. (You can also give it a simple variable wrapped in parentheses, but not a full expression involving a non-existant variable.) Not much use for that, either.

  5. This is the controversial one. When you access a property of an object which doesn't exist, you don't immediately get an error like in every other language. Instead you get an undefined object. (And then when you try to use that undefined object later on in the script it'll go wrong in a weird way that's much more difficult to track down than if JavaScript had just thrown an error straight away.)

    This is often used to check for the existence of properties:

    if (o.prop!==undefined) // or often as truthiness test, if (o.prop) ...do something...

    However, because you can assign undefined like any other value:

    o.prop= undefined;

    that doesn't actually detect whether the property is there reliably. Better to use the in operator, which wasn't in the original Netscape version of JavaScript, but is available everywhere now:

    if ('prop' in o) ...

In summary, undefined is a JavaScript-specific mess, which confuses everyone. Apart from optional function arguments, where JS has no other more elegant mechanism, undefined should be avoided. It should never have been part of the language; null would have worked just fine for (2) and (3), and (4) is a misfeature that only exists because in the beginning JavaScript had no exceptions.

what does if (!testvar) actually do? Does it test for undefined and null or just undefined?

Such a ‘truthiness’ test checks against false, undefined, null, 0, NaN and empty strings. But in this case, yes, it is really undefined it is concerned with. IMO, it should be more explicit about that and say if (testvar!==undefined).

once a variable is defined can I clear it back to undefined (therefore deleting the variable).

You can certainly assign undefined to it, but that won't delete the variable. Only the delete object.property operator really removes things.

delete is really meant for properties rather than variables as such. Browsers will let you get away with straight delete variable, but it's not a good idea and won't work in ECMAScript Fifth Edition's strict mode. If you want to free up a reference to something so it can be garbage-collected, it would be more usual to say variable= null.

can I pass undefined as a parameter?

Yes.

I have a web service to write that takes 7 parameters. Each is an optional query attribute to a sql statement wrapped by this web service. So two workarounds to non-optional params come to mind... both pretty poor:

method1(param1, param2, param 3, param 4, param 5, param 6, param7) method1(param1, param2, param3, param 4, param5, param 6) method 1(param1, param2, param3, param4, param5, param7)... start to see the picture. This way lies madness. Way too many combinations.

Now for a simpler way that looks awkward but should work: method1(param1, bool useParam1, param2, bool useParam2, etc...)

That's one method call, values for all parameters are required, and it will handle each case inside it. It's also clear how to use it from the interface.

It's a hack, but it will work.

I got an email asking for my opinion about when to use keyword arguments.

I thought I’d expand my answer into a full article about Ruby method arguments so everyone can benefit!

Ruby is very flexible when it comes to method arguments.

We have everything:

From the standard required arguments to optional arguments & even keyword (named) arguments.

In this article, you’re going to learn about the differences between all these argument types, and which ones to use depending on your situation.

Using the right kind of arguments will make your code easier to read & easier to work with.

When in Doubt Use Standard Arguments

Required arguments are what you get by default.

Here’ an example:

def write(file, data, mode) end write("cats.txt", "cats are cool!", "w")

If you don’t pass the exact number of arguments required you’ll get this familiar error message:

write("shopping_list.txt", "bacon") ArgumentError: wrong number of arguments (2 for 3)

This means that you gave the method 2 arguments, but it needs 3!

Flexible Methods With Optional Arguments

You may want to make some of your arguments optional by providing a default value.

For example:

def write(file, data, mode = "w") end

Now you can call write with 2 arguments, in which case mode will equal the default value ("w"), or you can pass in 3 arguments to override the default value & get different results.

This default value saves you some work when calling this method while still giving you the option to change it.

Use Keyword Arguments to Increase Clarity

One of the downsides of required & default arguments is that they are order dependent.

Meaning that you have to pass in the arguments in the same order

If you pass them in the wrong order:

You’ll get unexpected results!

For example, in the write method, you have to call it with the file first, then the data & finally the mode.

def write(file, data, mode) end

Keyword arguments allow you to vary the order of the arguments.

Here’s an example:

def write(file:, data:, mode: "ascii") end

This allows you to call the method in a different order:

write(data: 123, file: "test.txt")

But more importantly, when you call the method you can clearly see the meaning of the arguments.

I don’t find myself using keyword arguments very often, but they can be useful when you want to add clarity to method calls.

Let’s say that we have a Point class.

You could write it like this:

class Point def initialize(x: , y:) @x, @y = x, y end end point = Point.new(x: 10, y: 20)

This way there is no possible confusion about which of the two numbers (10 & 20) correspond to the x value or the y value.

That’s one of your main goals when writing code, to avoid confusion & misunderstanding as much as possible.

If using keyword arguments helps you do that then use them.

Think about this:

“Will adding keyword arguments make this easier to understand or will it add extra work & clutter to my code?”

Another thing about keyword arguments is that they are very explicit about the arguments you are missing.

Example:

point = Point.new # missing keywords: x, y

You can also combine keyword arguments with regular arguments.

One strategy I’ve been observing on Ruby built-in methods is that new versions tend to add new, optional arguments, as keyword arguments.

Examples of this are the keyword arguments for Float#round, Kernel#clone & String#lines introduced in Ruby 2.4.

Use Variable Arguments to Capture as Many Values as Necessary

What if you want to take an unlimited amount of values?

Then you can use variable arguments:

def print_all(*args) end print_all(1, 2, 3, 4, 5)

This allows you to call the method with any number of arguments, including none. A variable argument is an array with all the values passed to it.

You can combine this with other types of arguments.

Example:

def print_all(title, *chapters) end

This will take the 1st argument as title, and the rest as the chapters array. Notice that a variable argument needs to be after all your required & optional arguments, and before any keyword arguments.

Use The Correct Order

Here’s the valid order of arguments if you want to combine them & avoid a syntax error:

required -> optional -> variable -> keyword

Here’s a method that shows every possible argument type:

def testing(a, b = 1, *c, d: 1, **x) p a,b,c,d,x end testing('a', 'b', 'c', 'd', 'e', d: 2, x: 1)

The **x is the same as variable arguments, but for keyword arguments. It will be a hash instead of an array.

The Catch-All Argument

In some rare occasions you may see this:

def print_all(*) end

This means that the method is accepting any arguments, but it’s not doing anything with them. It’s similar to using the underscore character (_) inside a block to show which arguments you aren’t using.

A practical use for this could be in combination with the super keyword:

class Food def nutrition(vitamins, minerals) puts vitamins puts minerals end end class Bacon < Food def nutrition(*) super end end bacon = Bacon.new bacon.nutrition("B6", "Iron")

Now when Food’s nutrition changes its argument list, you don’t have to change arguments in Bacon too.

Summary

You’ve learned about Ruby’s powerful method arguments & how to use them! Required arguments are a good start, then you can add flexibility with optional arguments & add clarity with keyword arguments.

Hope you found this useful & interesting!

Share this post on Twitter so more people can see it 🙂