The former (strict) seems more explicit, perhaps safer, and perhaps more performant -- as there are little or no overheads for type checking or type conversion. But the latter (ad hoc) feels simpler looking at it from the outside, in that it "just works" with whatever argument the API consumer finds convenient to pass to it.

For the answer to this question, I'd like to see specific pros and cons to either approach (or to a different approach altogether, if neither is ideal), that Sue should know which approach to take when designing her library's API.

5 Answers
5

Some pros and cons

A smaller polymorphic interface is easier to read. I only have to remember one method.

It goes with the way the language is meant to be used - Duck typing.

If it's clear which objects I want to pull a rabbit out of, there shouldn't be ambiguity anyway.

Doing a lot of type checking is considered bad even in static languages like Java, where having plenty of type checks for the type of the object makes ugly code, should the magician really need to differentiate between the type of objects he's pulling a rabbit out of?

Pros for ad-hoc:

It's less explicit, can I pull a string out of a Cat instance? Would that just work? if not, what is the behavior? If I don't limit the type here, I have to do so in the documentation, or in the tests which might make a worse contract.

You have all the handling of pulling a rabbit in one place, the Magician (some might consider this a con)

Some alternative solutions:

In my opinion, this sort of design isn't very 'Java-Scripty' to begin with. JavaScript is a different language with different idioms from languages like C#, Java or Python. These idioms originate in years of developers trying to understand the language's weak and strong parts, what I'd do is try to stick with these idioms.

There are two nice solutions I can think of:

Elevating objects, making objects "pullable", making them conform to an interface on run-time, then having the Magician work on pullable objects.

Using the strategy pattern, teaching the Magician dynamically how to handle different type of objects.

Solution 1: Elevating Objects

One common solution to this problem, is to 'elevate' objects with the ability to have rabbits pulled out of them.

That is, have a function that takes some type of object, and adds pulling out of a hat for it. Something like:

I can make such makePullable functions for other objects, I could create a makePullableString, etc. I'm defining the conversion on each type. However, after I elevated my objects, I have no type to use them in a generic way. An interface in JavaScript is determined by a duck typing, if it has a pullOfHat method I can pull it with the Magician's method.

Elevating objects, using some sort of mixin pattern seems like the more JS thing to do.
(Note this is problematic with value types in the language which are string, number, null, undefined and boolean, but they're all box-able)

Solution 2: Strategy Pattern

This would allow you to add the abilities to pull rabbits out of various objects at run time, and would create very JavaScript'y code. A magician can learn how to pull objects of different types out of hats, and it pulls them based on that knowledge.

This way, you benefit from both worlds, the action of how to pull isn't tightly coupled to either the objects, or the Magician and I think this makes for a very nice solution.

Usage would be something like:

var m = new Magician();//create a new Magician
//Teach the Magician
m.learnToPull("",function(){
return "Pulled a rabbit out of a string";
});
m.learnToPull({},function(){
return "Pulled a rabbit out of a Object";
});
m.pullRabbit(" Str");

The problem is that you're trying to implement a type of polymorphism that doesn't exist in JavaScript - JavaScript is almost universally best treated as a duck-typed language, even though it does support some type faculties.

To create the best API, the answer is that you should implement both. It's a bit more typing, but will save a lot of work in the long run for users of your API.

pullRabbit should just be an arbiter method that checks types and calls the proper function associated with that object type (e.g. pullRabbitOutOfHtmlElement).

That way, while prototyping users can use pullRabbit, but if they notice a slowdown they can implement the type checking on their end (in likely a faster way) and just call pullRabbitOutOfHtmlElement directly.

This is JavaScript. As you get it better at it you'll find there's often a middle-road that helps negate dilemmas like this. Also, it really doesn't matter whether an unsupported 'type' is caught by something or breaks when somebody tries to use it because there is no compile vs. run-time. If you use it wrong it breaks. Trying to hide that it broke or make it work half-way when it broke doesn't change the fact that something is broken.

So have your cake and eat it too and learn to avoid type confusion and unnecessary breakage by keeping everything really, really obvious, as in well-named and with all the right details in all the right places.

First of all, I highly encourage getting into the habit of getting your ducks in a row before you need to check types. The leanest and most efficient (but not always best where native constructors are concerned) thing to do would be to hit the prototypes first so your method doesn't even have to care about what supported type is in play.

Note: It's widely regarded as bad form to do this to Object as everything inherits from Object. I personally would avoid Function too. Some might feel antsy about touching any native constructor's prototype which might not be a bad policy but the example could still serve when working with your own object constructors.

I wouldn't worry about this approach for such a specific-use method that's not likely to clobber something from another library in a less complicated app but it's a good instinct to avoid asserting anything overly generally across native methods in JavaScript if you don't have to unless you're normalizing newer methods in out-of-date browsers.

Fortunately, you can always just pre-map types or constructor names to methods (beware IE<=8 which doesn't have <object>.constructor.name requiring you parse it out of the toString results from the constructor property). You're still in effect checking constructor name (typeof is kind of useless in JS when comparing objects) but at least it reads much nicer than a giant switch statement or if/else chain in every call of the method to what could be a wide variety of objects.

A good general principle in any language IMO, is to try to sort out branching details like this before you get to code that actually pulls the trigger. That way it's easy to see all of the players involved at that top API level for a nice overview, but also much easier to sort out where the details somebody might care about are likely to be found.

Note: this is all untested, because I assume nobody actually has an RL use for it. I'm sure there's typos/bugs.

This (to me) is an interesting and complicated question to answer. I actually like this question so I will do my best to answer. If you do any research at all into standards for javascript programming, you will find as many "right" ways of doing it as there are people touting the "right" way of doing it.

But since you're looking for an opinion as to which way is better. Here goes nothing.

I personally would prefer the "adhoc" design approach. Coming from an c++/C# background, this is more my style of development. You can create the one pullRabbit request and have that one request type check the argument passed in and do something. This means you dont have to worry about what type of argument is being passed in at any one time. If you use the strict approach, you would still need to check which type the variable is but instead you would do that before you make the method call. So in the end the question is, do you want to check the type before you make the call or after.

I hope this helps, please feel free to ask more questions in relation to this answer, I will do my best to clarify my position.

When you write, Magician.pullRabbitOutOfInt, it documents what you thought about when you wrote the method. The caller will expect this to work if passed any Integer. When you write, Magician.pullRabbitOutOfAnything, the caller doesn't know what to think and has to go digging into your code and experimenting. It might work for an Int, but will it work for a Long? A Float? A Double? If you are writing this code, how far are you willing to go? What kinds of arguments are you willing to support?

Strings?

Arrays?

Maps?

Streams?

Functions?

Databases?

Ambiguity takes time to understand. I'm not even convinced that it's faster to write:

OK, so I added an exception to your code (which I highly recommend) to tell the caller that you never imagined they would pass you what they did. But writing specific methods (I don't know if JavaScript lets you do this) is no more code and much easier to understand as the caller. It sets up realistic assumptions about what the author of this code thought about, and makes the code easy to use.

Just letting you know that JavaScript lets you do that :)
–
Benjamin GruenbaumMay 30 '13 at 16:21

If hyper-explicit were easier to read/understand, how-to books would read like legalese. Also, per-type methods that all roughly do the same thing are a major DRY foul to your typical JS dev. Name for intent, not for type. What args it takes should either be obvious or very easy to look up by checking at one place in the code or in a list of accepted args at one method name in a doc.
–
Erik ReppenJun 1 '13 at 0:57