Do you use "return" to describe a function?

Hello,

here is a quite superficial question, but I often run into it when writing documentation. Consider the documentation of Float.abs and Int.abs in the ocaml manual:

Float.abs : float -> float

abs f returns the absolute value of f.

Int.abs : int -> int

abs x is the absolute value of x.

What would be the reason for choosing “return” instead of “is”? (or vice-versa) Which one is preferable?

1 Like

I very much prefer the latter, as it emphasizes the “what” over the “how”, which IMO better fits the functional paradigm as opposed to the imperative one.

8 Likes

My 2c:

It depends on the context. While is can be used to good effect with pure functions to suggest equational reasoning, return is the correct term for a machine procedure and can always be used.

Cheers,
Nicolas

7 Likes

I would say it depends on how you read the documentation as an english phrase. OCaml is an expression oriented language (compare to statement oriented) and, as such, an OCaml expression can be seen as nominal group or noun-phrase (see the chapter expression and the linguistic of programming language of this book). Therefore your two documentations sound like these english phrases:

The king of England returns Charles III

The king of England is Charles III

The expression f x is the subject of the phrase and, unless it is a function, it can’t return anything; but it can be equal to something, as in the second documentation comment. Saying that Float.abs f returns something is an abuse of language, it is Float.abs (the function, seen as the subject of the verb) that returns the absolute value of its argument.

4 Likes

Yes that was my idea too, on the other hand one could argue that “the call to” Float.abs f does “return” something

As, I said It depends on how you read the English sentence. What I wanted to point is that an OCaml well-formed expression can be used (as a foreign language expression) in the expression based english natural language. As you can do in the sentence: “2 + 3 is an algebraic notation for the sum of two and three”.

The verb “to be” in English can be used to express the identity of two things (The king of England is Charles III) or the copula in the relation between a subject and a predicate (Socrates was a Greek philosopher). The second usage is the one of the colon : in an OCaml expression: i : int means i is an int. This way when you embed an OCaml expression in an English sentence, you should use it with a verb that make sense: the expression Float.abs f is a float and, as such, can not return anything. You could for instance write: Float.abs f is a float representing the absolute value of x.

There is also some similarities in how work natural language and expression based programming language. I don’t know how it is done in other country but, in France, we give exercise to child with sentences with holes in them in order to learn the grammar and how to form correct phrases. For instance, we give them the sentence:

____  eat ____

and with it they could form the sentences:

the cat eats the mouse
the mouse eats the cheese

and so one. In principle, this is similar to string interpolation. But, more fundamentally, such an hole-phrase is equivalent to a lambda-abstraction, and filling the hole is just application and some steps of beta-reduction. And, as with referential transparency, we can replace a term with an equivalent one without changing its meaning:

The king of England is married to Camilla Parker Bowles
Charles III is married to Camilla Parker Bowles

In the book quoted in my previous message, the author (a linguist) refers to the indian grammarian Pāṇini. INRIA hosted a web site of a project headed by Gérard Huet: The Sanskrit Heritage Site based on Pāṇini grammar, and the author has developped the OCaml zen library for this project. Gérard Huet is known for his famous article on the zipper functional data structure, but he also was the thesis director of @xavierleroy . :wink:

In his personnal website, there is a transcription of a conference he gave entitled Foundations of computer science, at the crossroads of mathematics, logic and linguistics. The document is in french and in the format docx (I have a pdf version but I don’t know if I have the right to distribute it). What I find interesting, for the case at hand, is how he shows the correspondence between logic, grammar analyses, typing of functional programming and modus ponens. At the end of the article, he studies the sentence:

the cat eats the mouse

and he shows that to verify the sentence is well-formed is as if we have typed the verb eat this way eat : noun -> noun -> phrase.

After re-reading, I realize that my previous message is rather obscure and lacks clarity.

The verb “return” denotes an action, so the subject must be interpreted as being able to perform this action. Hence a possible reading as “a call to f x returns something”. That said, such a reading is more common in imperative languages, where it’s common to look at a program as a series of instructions for the computer. In a functional language, a pure expression (without side effects) is more commonly seen as representing a value that doesn’t necessarily perform any action (like a float). In this case, my personal taste is to document on what the expression represents, and then use the verb “to be” if appropriate to describe the result of the function call.

In any case, when the OCaml expression is used for its side effects, it seems appropriate to use an action verb to document it. To continue the analogy with grammatical analysis, such an expression will often be represented by a transitive verb: a verb that needs an object complement to express its action. In OCaml type language, this could be translated as:

type 'a verb = 'a -> unit

Such an action can be executed several times with this combinator:

let times n f x = for i = 1 to n do (f x : unit) done

If we look to the type of times we get:

val times : int -> ('a -> unit) -> 'a -> unit

and if we use our previous type aliases:

val times : int -> 'a verb -> 'a verb

In grammar, a term that takes a verb and modifies its meaning is called an adverb. In OCaml, this would be:

type 'a adverb = 'a verb -> 'a verb

In the end, for times we would have:

val times : int -> 'a adverb

which corresponds to the grammatical function of the word “times” in English.

let write = print_endline

The following expression can be documented in this way:

(* `times n write text` writes n times `text` to stdout *)

What’s fun (pun intended) is that the documentation is a paraphrase of the OCaml code with a slight morphological variation. And indeed, that’s what the instruction does:

times 5 write "OCaml is awesome";;
OCaml is awesome
OCaml is awesome
OCaml is awesome
OCaml is awesome
OCaml is awesome
- : unit = ()

(* increment five times a reference *)
let x = ref 0 in times 5 incr x; !x;;
- : int = 5
1 Like

Interesting discussion, which totally misses the point.

It depends what you are describing. So the difference is whether you are talking about the function f or the value f(x). f does return something, but f(x) is a value. The phrase f(x) returns... sounds at least awkward.
And the difference isn’t between functional and imperative languages, but whether the language (always) uses named parameters or not.

// Return true, if a - b/(c +8*d) == 0
function f(a, b, c, d) 
// Return true, if the first argument - the second argument....
Or
// f(a, b, c, d) is true, if... 
f: int -> int -> int -> int -> int

Sorry to be pedantic, but no, it is certainly not a value. “Value” has a very precise meaning when you talk about programing languages. The expression f x denotes the application of x to f. Even when both f and x are values, that does not make f x a value. A value is the result of an evaluation. You only get a value once f x has been evaluated. And in a language like OCaml which is effectful, making a distinction between expressions and values is even more critical.

So, going back to the original example, the proper sentence would be something like “the evaluation of abs x produces the absolute value of x”. This is a mouthful, so shortening that sentence to “abs x returns the absolute value of x” is a bit awkward but it makes sense. Saying that “abs x is the absolute value of x” is another possibility, but it feels just as awkward, because it completely disregards the fact that there is an actual computation involved. So, in a sense, it is a trade-off between concisely conveying some property and not abusing the language too much.

That said, there are cases where using “is” actually conveys a meaningful property. That is when it involves the identity of entities. For instance, “fst x is the first component of the pair x”, because they are physically the same thing.

2 Likes

Of course you are correct, but :wink: in reality the difference is between telling what the result is and what the function “does”. And the deciding factor is mostly what is easier to use for the writer (and sometimes what is thought of to be easier to comprehend for the reader).

So talking about “f returns the absolute value of it’s argument” vs. “f returns its argument if this argument is non-negative, and the additive inverse else.” Or “f(x) is the absolute value of x” vs. “f(x) additively invertes x if x is negative and yields x else”.

But anyway, the point I’ve been trying to make is that the formulation mostly is because of OCaml not (always) having named parameters and the need to somehow name them in the docstring.

1 Like

I guess the first question to ask is how you read/pronounce “f(x)” (or “f x” or whatever).
If it is “f at x” “f at x returns BLA” is awkward and should be “f returns BLA at x” which might be a awkward too for a “long” BLA.

I think if you look at real-world code in practice people commonly mix all these terminologies. Even in the same module. Eg look at Zarith/z.mli at master · ocaml/Zarith · GitHub which I’d consider pretty idiomatic. So I think the answer is ‘all wordings are valid in practice’.

2 Likes

Notice how Zarith’s documentation uses “returns something”, “computes something”, “is the same as something”, “is equal to something”. But it never uses “is something”.

Because they use “Something” instead.

Or “Something f”.

The question of the original poster was: which is preferable between “foo returns something” and “foo is something”? My point is that Zarith’s documentation, which was presented as being idiomatic, never uses “foo is something”. Sure, it sometimes uses just “something”, but that is not what the original question is about.

Yes, but that is just Zarith. The OCaml documentation itself uses “is” for the same functions.

val add : int -> int -> int
add x y is the addition x + y.

https://ocaml.org/manual/5.2/api/Int.html

And this is, because the OCaml documentation uses e.g. add x y, whereas Zarith mostly just talks about the function add itself.

The OCaml standard library documentation also uses a mix of various terminologies. They don’t enforce a consistent style for this.

Exactly. As I’ve said, a “consistent style” isn’t helpful. The “style” depends on what you are describing (or trying to describe).

Describing e.g. Mutexes using “is” would be quite strange and it doesn’t return anything (yes, yes, unit). So we describe what the function “does”.

val lock : t -> unit
Lock the given mutex. Only one thread can have the mutex locked at any time. A thread that attempts to lock a mutex already locked by another thread will suspend until the other thread unlocks the mutex.

https://ocaml.org/manual/5.2/api/Mutex.html

Or Random:

Again, “is”, like “bits is 30 random bits in a nonnegative integer” sound off. But it does return something, so use “return”.

val bits : unit -> int
Return 30 random bits in a nonnegative integer.

https://ocaml.org/manual/5.2/api/Random.html

1 Like

For sure, and that’s what I said in my first comment. :wink:

If you read the comment such that Float.abs is the subject of the verb, then that’s what you are describing. I consider this abuse of language more natural in an imperative language, because return is most of the time a keyword of those languages, and that’s the last action a function call will perform.

I would add that, even if it’s an abuse of language, I find it perfectly acceptable in order to avoid contrived documentation comment.