fsharp / fsharp/fslang-suggestions

Define properties using `let public`

Open
#811 7 comments 9 reactions 0 assignees View on GitHub
area: object-programming
Dominant language
No language data
Stars
373
Forks
21
PR merge metrics
No merged PRs in 30d

Description

# Define properties [edit: and public fields] using `let public`

An example class with current syntax:

```fsharp
type A() =
let u = 0
static let v = 1
member _.U = u
member t.W(i) = t.X + i + v
member t.X(i) = if i = 0 then 1 else t.X(i-1) * v
static member Y(i) = i + v
```
I propose we add `let public` syntax to expose properties. The class could then be rewritten as:
```fsharp
type A() =
let public U = 0
static let v = 1
let rec public X(i) = if i = 0 then 1 else X(i-1) * v
let public W(i) = X + i + v
static let public Y(i) = i + v
```

## Pros and Cons

### Pros:

1.
a) The common pattern `let u = ...` followed by `member _.U = u` can be replaced by the single line `let public u = ...`.
b) The cumbersome `_.` unused bindings are not present. (They would also be removed if https://github.com/fsharp/fslang-suggestions/issues/626 is implemented.)
2. Sequential ordering with explicit recursion is enforced, as usual in F# code, with the usual benefit of being able to understand code by reading it in sequentially. (Note that the second version swaps W and X and is easier to understand as a result.)

Current F# class code is a tradeoff between 1. and 2. If you use more `let u = ...; member _.U = u` you get the benefits of code order at the expense of verbosity. This suggestion would remove that tradeoff.

### Cons:

1. The public API of a class can no longer be found by looking at the bottom of the class definition.
2. It's another way of doing the same thing, and properties with setters would still need to be implemented with the current `member...` syntax.

## Notes

`let public U = f()` would be equivalent to `let u = f()` followed by `member _.U = u`, so `f()` is only evaluated once.

There would be no way to replicate `member _.SayHello = printf "hello world"` using this syntax, although `member _.SayHello() = printf "hello world"` could be done as `let public SayHello() = ...`. Arguably this is an advantage as the fact that properties without arguments execute their bodies whenever called is a fact that can surprise beginners and catch out experienced users.

## Extra information

Estimated cost (XS, S, M, L, XL, XXL):

L

## Affidavit (please submit!)

Please tick this by placing a cross in the box:
* [ x ] This is not a question (e.g. like one you might ask on [stackoverflow](http://stackoverflow.com)) and I have searched stackoverflow for discussions of this issue
* [ x ] I have [searched both open and closed suggestions on this site](http://github.com/fsharp/fslang-suggestions/issues) and believe this is not a duplicate
* [ x ] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:
* [ x ] This is not a breaking change to the F# language design
* [ x ] I or my company would be willing to help implement and/or test this

Contributor guide

No contributing guide indexed for this repository

Research direction

No implementation files, tests, or entry points are named in the issue. Before picking it up, establish where F# class `let` and `member` syntax is parsed and tested; done would require an accepted design, implementation, and tests for the proposed forms.

Written by the indexing model from the issue text.

Assessment

Tech stack
fsharp
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.