Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace (nearly) all ref cells in the compiler with mutable values #8063

Merged
merged 3 commits into from
Jan 7, 2020

Conversation

cartermp
Copy link
Contributor

@cartermp cartermp commented Jan 1, 2020

The large majority of ref cells in the compiler codebase are trivially replaceable with mutable values. A few are not, and so those are mostly left untouched. I think this helps with codebase readability.

Excludes test code

@cartermp cartermp changed the title Replace (nearly) all ref cells with mutable values [WIP] Replace (nearly) all ref cells with mutable values Jan 1, 2020
@cartermp cartermp changed the title [WIP] Replace (nearly) all ref cells with mutable values Replace (nearly) all ref cells with mutable values Jan 3, 2020
@cartermp cartermp changed the title Replace (nearly) all ref cells with mutable values Replace (nearly) all ref cells in the compiler with mutable values Jan 3, 2020
@NatElkins
Copy link
Contributor

Is there any performance benefit to this? Or is it just a stylistic change?

@cartermp
Copy link
Contributor Author

cartermp commented Jan 3, 2020

Mostly stylistic, and most of the uses seem to predate let mutable. In many cases this is a micro optimization since it avoids a small heap allocation, but in it won't make a noticeable difference.

@heronbpv
Copy link

heronbpv commented Jan 3, 2020

Taking the opportunity to also make a question: is there any remaining case (or cases) where usage of a ref cell is recommended over a mutable let?

src/fsharp/NameResolution.fs Outdated Show resolved Hide resolved
@cartermp
Copy link
Contributor Author

cartermp commented Jan 3, 2020

@heronbpv There are, but I'd say the uses are limited. The syntax just looks kind of wonky and the dereference operator ! is just plain confusing to people.

For bogstandard mutation that's local to a function or method, typically done for perf reasons, mutable values are preferred. Same goes for ref in a record label versus just making it a mutable label.

I'd also say that using a byref<'T> to mutate when passing by reference is also preferred. However, this does mean you are constrained in a few ways:

  • Taking an address of something with & only gives a byref<'T> on let mutable-bound values. It will produce an inref<'T> for everything else, which is readonly.
  • You cannot use higher-order functions with the data you're mutating
  • You cannot allow a reference to escape the scope it was declared in

In those cases, you'll need to declared something as a ref if you need to "pass this thing by reference" as a scenario.

Additionally, tupled values for DUs do not support mutable values, so you need to declare them as a ref if you want a DU case that can be mutated.

type DU =
    | A of int * mutable int // Not supported, needs to be 'int ref'
    | B of int * string

Additionally, there is a pattern in this codebase where a value is locked via lock and mutated within the lock expression. It's fairly convenient to just lock on a ref cell to the value being mutated within a lock:

lock enumeratorR (fun () ->
prefix.Clear()
begin match !enumeratorR with
| Some (Some e) -> IEnumerator.dispose e
| _ -> ()
end
enumeratorR := None)

Finally, there are some cases where a mutable value will actually be converted into a ref cell, such as enclosing the value in a lambda function that is also the return value:

let f =
    let mutable x = 0
    fun _ -> x <- x + 1
    
let g =
    let x = ref 0
    fun _ -> x := !x + 1
    
f()
f()
g()
g()

Both function values are equivalent.

This is getting into pretty niche territory though.

I'd say that these cases tend to be pretty niche in F# programming, since mutating values is usually done local to a function or method and done for performance reasons. In those cases, let mutable generally looks cleaner and avoids an additional allocation.

@heronbpv
Copy link

heronbpv commented Jan 3, 2020

Thanks for the answer, @cartermp !

@KevinRansom
Copy link
Member

@cartermp , this is good work. I will mark it approved, and leave it to you to deal with:

   let mutable table = mtyp.ActivePatternElemRefLookupTable
    cacheOptRef &table (fun () ->

I think just reverting the change should be good enough.

Kevin

Copy link
Member

@KevinRansom KevinRansom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subject to you dealing with:

   let mutable table = mtyp.ActivePatternElemRefLookupTable
    cacheOptRef &table (fun () ->

@cartermp
Copy link
Contributor Author

cartermp commented Jan 6, 2020

@KevinRansom Thanks, yeah it's been kinda fun digging through what are surely some of the older parts of the codebase. The isFirst function is my personal favorite.

src/fsharp/CompileOps.fs Show resolved Hide resolved
src/fsharp/CompileOptions.fs Outdated Show resolved Hide resolved
@cartermp
Copy link
Contributor Author

cartermp commented Jan 6, 2020

I will incorporate parts of #8062 into this

# This is the 1st commit message:

ref -> mutable in more places in the compiler

# The commit message dotnet#2 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191229.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19629.1

# The commit message dotnet#3 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191230.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19630.1

# The commit message dotnet#4 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191231.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19631.1

# The commit message dotnet#5 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20200101.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.20051.1

# The commit message dotnet#6 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191216.5 (dotnet#8079)
#
# - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19616.5

# The commit message dotnet#7 will be skipped:

# dispose fsi at the end of a scripting session (dotnet#8084)
#

# The commit message dotnet#8 will be skipped:

# Added static link tests and extended CompilerAssert (dotnet#8101)
#
# * Changed CompilerAssert to static class. Added Compile/Execute methods that take a Compilation description. Added static link tests
# 
# * Hiding compilation description internals
# 
# * Added another test to check for sanity
# 
# * Making a few optional parameters
# 
# * Hiding internals of CompilationReference

# The commit message dotnet#9 will be skipped:

# Parameterize product version (dotnet#8031)
#
# * Parameterize Product details
# 
# * fcs
# 
# * Repack pkgdef
@cartermp cartermp closed this Jan 7, 2020
@cartermp cartermp reopened this Jan 7, 2020
@cartermp cartermp merged commit f9ea582 into dotnet:master Jan 7, 2020
@forki
Copy link
Contributor

forki commented Jan 7, 2020

Great work

@cartermp
Copy link
Contributor Author

cartermp commented Jan 7, 2020

Just need to figure out why some parts of absil are so touchy :)

nosami pushed a commit to xamarin/visualfsharp that referenced this pull request Feb 23, 2021
…otnet#8063)

* # This is a combination of 9 commits.
# This is the 1st commit message:

ref -> mutable in more places in the compiler

# The commit message #2 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191229.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19629.1

# The commit message #3 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191230.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19630.1

# The commit message #4 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191231.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19631.1

# The commit message #5 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20200101.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.20051.1

# The commit message #6 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191216.5 (dotnet#8079)
#
# - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19616.5

# The commit message #7 will be skipped:

# dispose fsi at the end of a scripting session (dotnet#8084)
#

# The commit message #8 will be skipped:

# Added static link tests and extended CompilerAssert (dotnet#8101)
#
# * Changed CompilerAssert to static class. Added Compile/Execute methods that take a Compilation description. Added static link tests
# 
# * Hiding compilation description internals
# 
# * Added another test to check for sanity
# 
# * Making a few optional parameters
# 
# * Hiding internals of CompilationReference

# The commit message #9 will be skipped:

# Parameterize product version (dotnet#8031)
#
# * Parameterize Product details
# 
# * fcs
# 
# * Repack pkgdef

* no ilread
nosami pushed a commit to xamarin/visualfsharp that referenced this pull request Jan 26, 2022
…otnet#8063)

* # This is a combination of 9 commits.
# This is the 1st commit message:

ref -> mutable in more places in the compiler

# The commit message #2 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191229.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19629.1

# The commit message #3 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191230.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19630.1

# The commit message #4 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191231.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19631.1

# The commit message #5 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20200101.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.20051.1

# The commit message #6 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191216.5 (dotnet#8079)
#
# - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19616.5

# The commit message #7 will be skipped:

# dispose fsi at the end of a scripting session (dotnet#8084)
#

# The commit message #8 will be skipped:

# Added static link tests and extended CompilerAssert (dotnet#8101)
#
# * Changed CompilerAssert to static class. Added Compile/Execute methods that take a Compilation description. Added static link tests
# 
# * Hiding compilation description internals
# 
# * Added another test to check for sanity
# 
# * Making a few optional parameters
# 
# * Hiding internals of CompilationReference

# The commit message #9 will be skipped:

# Parameterize product version (dotnet#8031)
#
# * Parameterize Product details
# 
# * fcs
# 
# * Repack pkgdef

* no ilread
nosami pushed a commit to xamarin/visualfsharp that referenced this pull request Jan 26, 2022
…otnet#8063)

* # This is a combination of 9 commits.
# This is the 1st commit message:

ref -> mutable in more places in the compiler

# The commit message #2 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191229.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19629.1

# The commit message #3 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191230.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19630.1

# The commit message #4 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191231.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19631.1

# The commit message #5 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20200101.1
#
# - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.20051.1

# The commit message #6 will be skipped:

# Update dependencies from https://github.com/dotnet/arcade build 20191216.5 (dotnet#8079)
#
# - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19616.5

# The commit message #7 will be skipped:

# dispose fsi at the end of a scripting session (dotnet#8084)
#

# The commit message #8 will be skipped:

# Added static link tests and extended CompilerAssert (dotnet#8101)
#
# * Changed CompilerAssert to static class. Added Compile/Execute methods that take a Compilation description. Added static link tests
# 
# * Hiding compilation description internals
# 
# * Added another test to check for sanity
# 
# * Making a few optional parameters
# 
# * Hiding internals of CompilationReference

# The commit message #9 will be skipped:

# Parameterize product version (dotnet#8031)
#
# * Parameterize Product details
# 
# * fcs
# 
# * Repack pkgdef

* no ilread
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants