0

In many languages, it is common for a function to have multiple return values (as a tuple), such as:

def foo():
    return "Hello, World!", 0

I often do this when a computationally expensive (or an often called) function calculates multiple values. For example, a function that walks through an automaton to find the state for the longest prefix of a word contained in the automaton as well as the length of the prefix. A clean way of doing this would be to write two functions get_longest_prefix(word) and get_state(prefix), but it saves quite some computation to return both in one run.

The question is, what is the general approach, (or python convention), for naming such functions. Something like get_longest_prefix_and_len mostly results in too lengthy names.

4

A function is named for its purpose

The question's premise, i.e. what a function's name should reflect, isn't quite right. From your comment on candied_orange's answer:

What I am not satisfied with when using a [function] name such as those you suggested is that they are not descriptive of the [data type] being returned.

Function names should not describe their return value, at least not inherently. A function should describe what the function's purpose is.

If a function inherently needed to be named after what it returns, every function (that returns something) would need to be called returnFoo, returnBar, ... Clearly, this isn't all that useful if it were the primary naming rule.

There are cases where a function has no real purpose other than returning a value which is already trivially available, at which point it can be useful to name the function after the value it returns. But it's not a blanket rule that should be blindly applied.

When a function does something and then returns the subsequent result, the primary purpose is doing something, and returning the result is just a secondary consideration (since it'd be pointless to not return your achieved result, in most cases).

Think of it this way: if you want to return multiple values, you could approach this two different ways:

  • Wrap all needed return values in a DTO class and return an instance of that class
  • Return multiple values (for languages that support it).

In either case, the method does the exact same thing. The only thing that changes is the returned type(s). Following your logic, these methods should have different names, since they're returning different types.

That doesn't make sense. The function has the exact same purpose in either case, so its name should be unchanged.

The only valid justification for picking different function names is related to overload conflicts, i.e. in case you want to implement both methods and they have the same signature.
But this is not related to the question on what you should name a function when there is no overload conflict.


A function's purpose (and thus name) is contextual

In a question that solely focuses on naming decisions, you've not really focused on the most important information: context.

a function that walks through an automaton to find the state for the longest prefix of a word contained in the automaton as well as the length of the prefix

Notice your usage of "prefix" in describing both values. This strongly indicates that your multiple return values are all prefix-related information. This leads us to understand the purpose of your function: it finds a prefix and returns information on it.

a function that walks through an automaton to find the state for the longest prefix of a word contained in the automaton as well as the length of the prefix

The primary purpose of the function is to find the longest prefix. Returning data related to that prefix is a secondary consideration.

The name of the function should reflect its primary purpose:

def findLongestPrefix():
    return "Hello, World!", 0

Note: There may be a contextual name (e.g. "prefix details", "prefix information", ...) which is already defined/understood in your domain and reflects the information that you're trying to return here. If that is the case, such a contextual name would be better than the "prefix" name I chose to use here. You have more contextual awareness than me, so adapt my suggestion accordingly.

Note: I'm not sure which language you're using (python?) and what it's casing conventions are. Adjust the casing as appropriate.


Documenting the returned values

my concern for being indicative of the data structure remains, especially for dynamically typed languages such as python

I'm aware that this probably isn't applicable to Python, but C# specifically added named tuples to ensure that developers could give each value an appropriate name which describes each individual returned value. There is a clear benefit to labeling return values (when there is more than one).

Python doesn't allow for it (AFAIK), so you're going to have to live with that. This is a design consequence of the language you chose to use.

But as much as I agree that lack of clear typing can lead to issues like these in dynamically typed languages, I disagree that you should therefore foist this return type information in the method name itself.

While not impossible, it doesn't really fix the issue. You still don't get the benefits of strong typing, the function name still needs to be read and understood by humans, and if a human needs to look it up anyway (and gets no compiler validation), then proper function documentation trumps function naming. Don't try to inject documentation in the function name.

Instead of forcing a terse bit of information in the function name, instead you should clearly document this function and what it returns.

Whether documentation comments suffice or you instead use an external documentation tool is up to you and what your company prefers to use.

a name such as get_longest_prefix_data is at least indicative that the returned type is not just a string or a state, but a structured value, so it is not misleading at all, and encourages the developer to check to documentation

If you're a developer working in a language where there is no strongly typed return value, you'd have by default check a function (or its return type) to ensure that you know what to expect it to return.

There shouldn't be a need to name functions specifically so you can remind developers to look up documentation on things they aren't yet familiar with.

| improve this answer | |
  • This is a very well thought out response, that I mostly agree with. Couple of comments though: 1. Python does have namedtuples (and dataclasses). They are quite useful when moving data over modules, but they seem to be less preferred in local context. 2. In my experience, most developers do not check return types if they believe to be able to infer it from the name, therefore I prefer names that certainly do not convey such information to those which could be misleading. – Ali Rasim Kocal Dec 16 '19 at 18:22
2

Why did you bundle the return values together in the first place? Choose a name that makes that clear.

"walked through an automaton" inspires a name like getWalkedData()

If you're tuple stays focused on the prefix getPrefixData()

You absolutely do not need a name that describes each element in the tuple. You need to remind people what the tuple is about so they don't have to keep looking inside.

| improve this answer | |
  • I am bundling the values to avoid a second function call, as I need both and this function is called very often in an inner loop. What I am not satisfied with when using a name such as those you suggested is that they are not descriptive of the datetype being returned. – Ali Rasim Kocal Dec 14 '19 at 12:39
  • @AliRasimKocal better? – candied_orange Dec 14 '19 at 12:40
  • Yes, that's a good suggestion as a rule of thumb, however, my concern for being indicative of the data structure remains, especially for dynamically typed languages such as python. – Ali Rasim Kocal Dec 14 '19 at 12:42
  • @AliRasimKocal tuple names should not be indicative of each element, rather of the concept that brought them together. – candied_orange Dec 14 '19 at 12:44
  • 1
    It's not that we want them to be forced to check documentation. It's that we want the correct level of abstraction. Save element names for when you're breaking it out into the elements. And no rush with the check. Hope you get plenty of good answers. – candied_orange Dec 14 '19 at 12:55
0

... a function that walks through an automaton to find the state for the longest prefix of a word contained in the automaton as well as the length of the prefix

Or you could just write a class PrefixAutomaton that contains both the logic and the data and initializes itself appropriately.

That's not to say you must use OO for these cases - free functions may be fine. But grouping several data values with some invariants and related behaviour is the sort of situation classes were invented for.

| improve this answer | |
  • This function is a part of the initialization of a LexiconAutomaton class already. Since the algorithm to create a minimal automaton is complicated, it is divided into such smaller parts. I would create a (sub)class such as PrefixSearchResult in Java/C#, but it is quite unpythonic. – Ali Rasim Kocal Dec 16 '19 at 18:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.