Why is "do" allowed inside a function?
Asked Answered
P

2

10

I noticed that the following code compiles and works in VS 2013:

let f() =
    do Console.WriteLine(41)
    42

But when looking at the F# 3.0 specification I can't find any mention of do being used this way. As far as I can tell, do can have the following uses:

  • As a part of loop (e.g. while expr do expr done), that's not the case here.
  • Inside computation expressions, e.g.:

    seq {
        for i in 1..2 do
        do Console.WriteLine(i)
        yield i * 2
    }
    

    That's not the case here either, f doesn't contain any computation expressions.

    Though what confuses me here is that according to the specification, do should be followed by in. That in should be optional due to lightweight syntax, but adding it here causes a compile error (“Unexpected token 'in' or incomplete expression”).

  • Statement inside a module or class. This is also not the case here, the do is inside a function, not inside a module or a class.

I also noticed that with #light "off", the code doesn't compile (“Unexpected keyword 'do' in binding”), but I didn't find anything that would explain this in the section on lightweight syntax either.

Based on all this, I would assume that using do inside a function this way should not compile, but it does. Did I miss something in the specification? Or is this actually a bug in the compiler or in the specification?

Preservative answered 16/7, 2014 at 11:43 Comment(9)
It's called a do binding. I couldn't find it in the spec, but it's documented on MSDN.Cullin
@Cullin That's the third case I mentioned, do inside a module. “Use a do binding when you want to execute code independently of a functionPreservative
To finish the quote: independently of a function *or value definition*. The second case could be applicable within a function.Cullin
The definition of module-function-or-value-defn is possibly relevant here: module Foo = do () doesn't compile either with #light "off".Lennon
Independently of a function would describe top-level do bindings (in a module or class constructor). Other do bindings could appear anywhere a unit expression is allowed.Cullin
@Cullin In the spec, it's in §10.2.5 for modules and §8.6.1.3 for classes. In either cases, I didn't find anything about do bindings in functions.Preservative
@Lennon That's because you're using light syntax, module Foo = begin do () end does compile with #light "off".Preservative
Apparently it's missing from the spec.Cullin
The spec isn't 100% comprehensive.Fitzhugh
C
7

From the documentation on MSDN:

A do binding is used to execute code without defining a function or value.

Even though the spec doesn't contain a comprehensive list of the places it is allowed, it is merely an expression asserted to be of type unit. Some examples:

if ((do ()); true) then ()
let x: unit = do ()

It is generally omitted. Each of the preceding examples are valid without do. Therefore, do serves only to assert that an expression is of type unit.

Cullin answered 16/7, 2014 at 14:57 Comment(2)
I think the spec disallows it, since it isn't listed as one of the choices for expr (§6 and §A.2.3).Preservative
Over the past few years I've seen many examples of do used in a function or method. If this behavior isn't intentional, it is de facto valid at this point. However, I think that isn't the case and the spec is incomplete on this point.Cullin
J
0

Going through the F# 3.0 specification expression syntax has do expr as a choice of class-function-or-value-defn (types) [Ch 8, A.2.5] and module-function-or-value-defn (modules) [Ch 10, A.2.1.1].

I don't actually see in the spec where function-defn can have more than one expression, as long all but the last one evaluate to unit -- or that all but the last expression is ignored in determining the functions return value.

So, it seems this is an oversight in the documentation.

Johnny answered 17/7, 2014 at 1:57 Comment(1)
“I don't actually see in the spec where function-defn can have more than one expression” That's thanks to the expr = expr; expr rule and the fact that lightweight syntax makes the semicolon optional.Preservative

© 2022 - 2024 — McMap. All rights reserved.