Fsharp: Mutable use binding compiles

Created on 14 Jul 2018  Â·  11Comments  Â·  Source: dotnet/fsharp

open System.Drawing

let f() =
    use mutable font = new Font("Arial", 10.0f)
    font <- new Font("Arial", 11.0f)

f()

The above code compiles. Note that in C# it is not:

screen shot 2018-07-14 at 11 46 15

Using latest Mono and FCS from Ionide

Area-Compiler Feature Improvement

Most helpful comment

would be a new language suggestion

Please don't let us assign any meaning to this abomination, let's introduce a compiler error (if allowed due to spec) or introduce a warning.

All 11 comments

Also, I returned out the font here:

open System.Drawing

let f() =
    use mutable font = new Font("Arial", 10.0f)
    font <- new Font("Arial", 11.0f)
    font

f()

Which hangs FSI indefinitely when the above code is executed.

If I do not make it mutable, it executes:

open System.Drawing

let f() =
    use font = new Font("Arial", 10.0f)
    //font <- new Font("Arial", 11.0f)
    font

f()

Result:

val f : unit -> Font
val it : Font =
  [Font: Name=Arial, Size=10, Units=3, GdiCharSet=1, GdiVerticalFont=False]

So we definitely allow code that cannot execute correctly.

It's definitely should not compile, but it's a breaking change.

On Windows this doesn't seem to "hang" and the "semantics" of use mutable seem to be: "Call dispose on the last reference". So I'd assume this "hang" to be a mono bug.

Yep, looks like the hang is a mono issue, so adding a restriction on this would have to be a warning.

Actually, the right behaviour would be to call Dispose on the previously bind object just before assigning a new one (ideally, atomically), that's what Rust does:

#[derive(Debug)]
struct Foo(String);

impl Drop for Foo {
    fn drop(&mut self) {
        println!("Dropping {:?}", self)
    }
}

fn main() {
    {
        let mut foo = Foo("1".to_string());
        foo = Foo("2".to_string());
        foo = Foo("3".to_string());
    }
    println!("Done")
}
Dropping Foo("1")
Dropping Foo("2")
Dropping Foo("3")
Done

I'm with Vasily here but this would be a new language suggestion

Interestingly in the language spec 6.6.4 ‘use mutable’ doesn’t exist. So removing this thing would not be a breaking change in the spec...

would be a new language suggestion

Please don't let us assign any meaning to this abomination, let's introduce a compiler error (if allowed due to spec) or introduce a warning.

Seems like the compiler accepts pretty much everything with use it would with let:

module M =
    use internal d<'T> = { new System.IDisposable with member __.Dispose() = printfn "disposing 1, %O" typeof<'T>.Name }
    use rec d1 = { new System.IDisposable with member __.Dispose() = printfn "disposing 1" }
    and d2 = { new System.IDisposable with member __.Dispose() = printfn "disposing 2" }

At least we get:

stdin(82,5): warning FS0524: 'use' bindings are not permitted in modules and are treated as 'let' bindings
stdin(83,5): warning FS0524: 'use' bindings are not permitted in modules and are treated as 'let' bindings

But in principle the compiler seems to allow it (which is against the spec)

I'm not sure what to think here. Any change to this would be a breaking change. This is somewhat similar to my proposal on disabling let mutable x : byref<int> suggestion.

Agreed on this turning into a warning.

Was this page helpful?
0 / 5 - 0 ratings