Skip to content

Instantly share code, notes, and snippets.

@liammclennan
Created July 5, 2012 22:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save liammclennan/3056908 to your computer and use it in GitHub Desktop.
Save liammclennan/3056908 to your computer and use it in GitHub Desktop.
Named Method Arguments: From connascence of position to connascence of name

From wikipedia:

Two software components are connascent if a change in one would require the other to be modified in order to maintain the overall correctness of the system.

Connascence is a useful tool for discussing different types of coupling that occur within software.

Again from wikipedia, "connascence of name is when multiple components must agree on the name of an entity". Connascence of name one is of the list harmful and most unavoidable types of connascence because it is simple to reason about and change. While connascence of name is still connascence, and therefore bad, it is among the most amenable to refactoring. If the name of something changes then everything that refers to that thing by name must also change. This is a simple change that can be mostly statically determined and applied by tools.

Connascence of position is present when changing the order of something necessitates a change elsewhere. An example is the order of function arguments. If the order of a function's arguments is changed then every client of that function must also change. Connascence of position is worse than connascence of name (usually) because it is less explicit and therefore more difficult to reason about and successfully change.

From connascence of position to connascence of name

Some modern languages have slowly been migrating to connascence of name from connascence of position. As well as converting to a less harmful form of coupling this has the additional benefit of documenting the client-side of a method call.

Ruby

Ruby supports positional method arguments.

def full_name(first_name, middle_name, last_name)
    "#{first_name} #{middle_name} #{last_name}"
end

p full_name 'Eric', 'Arthur', 'Blair'
=> "Eric Arthur Blair"

but many ruby apis prefer the use of a single hash containing the method arguments:

def full_name(name)
    "#{name[:first]} #{name[:middle]} #{name[:last]}"
end

p full_name :first=>'Eric', :middle=>'Arthur', :last=>'Blair'
=> "Eric Arthur Blair"

this has the benefit of converting positional parameters to named parameters and therefore connascence of position to connascence of name.

JavaScript

JavaScript has adopted the same convention. While positional function arguments work:

function fullName(first, middle, last) {
    return first + ' ' + middle + ' ' + last;
}

fullName('Eric', 'Arthur', 'Blair');
=> "Eric Arthur Blair"

most apis favour named arguments by passing a single object containing the method arguments:

function fullName(name) {
    return name.first + ' ' + name.middle + ' ' + name.last;
}

fullName({ first: 'Eric', middle: 'Arthur', last: 'Blair'});
=> "Eric Arthur Blair"

C sharp

C# now supports named arguments, but there usage is not popular. C# and .net has a dependable history of adopting, after a delay, the technology and techniques that have become dominant on other platforms. Therefore, I predict that usage of named method arguments in C# will increase over the next few years. Interestingly, C# is the only one of the three languages discussed that has a specific language feature for named arguments and it is also the only one that does not require a change to the definition of the method to take advantage of named arguments. The decision to use or not use named arguments is entirely at the client's discretion.

string FullName(string first, string middle, string last) {
    return String.Format("{0} {1} {2}", first, middle, last);
}

FullName(first: "Eric", middle: "Arthur", last: "Blair");
=> "Eric Arthur Blair"
@adamchester
Copy link

Regarding c#, One of my pet hates about APIs is when they use Boolean arguments. I often want to use them by name, but still allow the other arguments to be found by position. Ideally, I would do as you suggest; named is generally better, but in many cases it hurts readability.

I've found that switching to using named arguments in more and more situations has been an overall improvement. I also find its harder to name the arguments succinctly, but putting that effort in is a good thing.

Also, r# seems to hadle refactoring both positional and named just fine.

@liammclennan
Copy link
Author

All good points. One option that I skipped is the combination of named and positional arguments. R# is clever enough to minimize the impact of a lot of connascence, which is great, but I still want to minimize it.

The main points I was making are: named parameters convert positional connascence to connascence of name, ruby and JavaScript have trended in this direction, .net tends to follow what everyone else does.

@adamchester
Copy link

C# doesn't mix the two well, one you go named, the remaining must be named.

@liammclennan
Copy link
Author

Seems like a reasonable constraint. From memory Ruby is similar.

@adamchester
Copy link

It is reasonable, except in the case I mentioned earlier; an API has a boolean argument, and your only reason for wanting to name it is to make the code readable.

string name = SomeApi.FullName(formatFirstLast: true, "abc", "def");

Of course, it's only a problem if you are calling an API you can't control. The person who wrote that API should be shot.

@thomasjo
Copy link

thomasjo commented Jul 6, 2012

What about the following alternate C# version?

string FullName(dynamic name) {
    return String.Format("{0} {1} {2}", name.First, name.Middle, name.Last);
}

FullName(new { First = "Eric", Middle = "Arthur", Last = "Blair" });
=> "Eric Arthur Blair"

@liammclennan
Copy link
Author

That is a lot like the JavaScript version. Not sure that the style will really take off. C# developers like their types.

@jkells
Copy link

jkells commented Jul 13, 2012

<3 my types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment