Skip to content

[Feature] New rule to prefer non-mutable property initialization #535

@knocte

Description

@knocte

Description

New rule to prefer non-mutable property initialization.

Testcases

Code that should be flagged:

  1. With a write-only property:
type SomeClass() =
    let mutable myInternalValue = 1
    // A write-only property.
    member this.MyWriteOnlyProperty with set (value) = myInternalValue <- value

module Program =
    let someInstance = SomeClass()
    someInstance.MyWriteOnlyProperty <- 2
  1. With a read-write property:
type SomeClass() =
    let mutable myInternalValue = 1
    // A read-write property.
    member this.MyReadWriteProperty
        with get () = myInternalValue
        and set (value) = myInternalValue <- value

module Program =
    let someInstance = SomeClass()
    someInstance.MyReadWriteProperty <- 2
  1. With a C# class:
module Program =
    // SomeCSharpClass implementation lives in a referenced assembly
    let someInstance = SomeCSharpClass()
    someInstance.MyReadWriteProperty <- 2
  1. Same as 2 but with a static method call (static invocations shouldn't affect the flagging):
type SomeClass() =
    let mutable myInternalValue = 1
    static member SomeStaticMethod() =
        () // any code goes here
    // A read-write property.
    member this.MyReadWriteProperty
        with get () = myInternalValue
        and set (value) = myInternalValue <- value

module Program =
    let someInstance = SomeClass()
    SomeClass.SomeStaticMethod()
    someInstance.MyReadWriteProperty <- 2

Code that should not be flagged:

  1. Using non-mutable property initialization (with a write-only property):
type SomeClass() =
    let mutable myInternalValue = 1
    // A write-only property.
    member this.MyWriteOnlyProperty with set (value) = myInternalValue <- value

module Program =
    let someInstance = SomeClass(MyReadWriteProperty = 2)
    1. Using non-mutable property initialization (with a read-write property):
type SomeClass() =
    let mutable myInternalValue = 1
    // A read-write property.
    member this.MyReadWriteProperty
        with get () = myInternalValue
        and set (value) = myInternalValue <- value

module Program =
    let someInstance = SomeClass(MyReadWriteProperty = 2)
  1. Mutating the class after using it:
type SomeClass() =
    let mutable myInternalValue = 1
    member this.SomeMethod() =
        () // some code here
    // A read-write property.
    member this.MyReadWriteProperty
        with get () = myInternalValue
        and set (value) = myInternalValue <- value

module Program =
    let someInstance = SomeClass()
    someInstance.SomeMethod()
    someInstance.MyReadWriteProperty <- 2
  1. Modules, not classes:
module SomeModule =
    let mutable myInternalValue = 1

module Program =
    SomeModule.myInternalValue <- 2

Granted, using non-mutable property initialization generates the same CIL code than the flagged code, but it looks better because it doesn't have the <- operator.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions