Use `_` to mark properties as private

Inspired by this Ppx to make names starting with _ (for example) - General - ReScript Forum (rescript-lang.org), I think this may not be a terrible idea.

But this may be a breaking change,

module N = {
  let _x = 3 
}

N._x -> Js.log // this code no longer compile, since `_x` is not accessible

Is this a big breaking change?

Pros

  • Much easier/robust to implement than the current %%private
  • More lightweight to use

Cons

  • minor breaking changes?

Neutral

  • No quick way to suppress the unused variable warnings, this may be a good thing
6 Likes

No quick way to suppress the unused variable warnings, this may be a good thing

If I’m using some API that takes a function with a lot of arguments that I don’t need, how would this look? For instance I have some code that looks like this:

<DialogTrigger>
  {(ref, onShow, _onHide, _onBlah, _onFoo, _onBar, _onBaz) => { ... }
</DialogTrigger>

Would I need to change all of the unused parameters to _? (I don’t think that would be a deal breaker for me; I just want to understand the proposal.)

1 Like

Some additional thoughts.

Pros:

  • Simple syntax for private declaration
  • It’s a convention used in some JS projects.

Cons:

  • Not friendly for newcomers reading ReScript code, it’s not intuitive what its purpose is.
  • Not all JS devs follow this convention for private.
  • Hard to search for this kind of syntax in documentation.
  • Not friendly for newcomers writing ReScript code, the underscore prefix may be used for other purposes, so a newcomer using it will have a frustrating surprise that behaviour is different from JS, and may have difficulty discovering why the behaviour is happening (due to previous point).
  • Making it part of ReScript is opinionated considering in JS it’s only a convention.

Overall, I’d propose that making this part of the language syntax moves ReScript away from JS, when ReScript’s strength is that it aims to align with JS.

Some other options:

[1] Decorator

Consistent with other ReScript code

@private let x = 0

[2] Keyword

Consistent with TypeScript private, a key target audience for ReScript.

private let x = 0

[3] JS spec

Part of the JS spec for private class members.

let #x = 0
9 Likes

I use leading underscore as an intuitive way of ignoring values (kind of documentation of what is this ignored value).
another thing I’ve to mention is from what I see leading underscore convention (for hiding stuff) is not that common in js community these days.
so although interfaces are enough for me I prefer having a keyword or attribute as an easier way to hide implementation rathar than leading underscore.

8 Likes

Yes, in JS this convention is rather outdated. Kevan specifies a couple of fresher approaches:

2 Likes

I think that keyword as in TS is the best way. Because it’s friendly and I see that it’s private instantly.

JS spec use # only in classes, and it doesn’t protected members. This is a controversial decision and I haven’t seen anyone using it.

private let x = 0 - is my choise!

PS underscore is better than js spec by my opinion

4 Likes

IMO whitelisting is better than blacklisting. It’s easier to accidentally leak a private thing (hard to notice) than accidentally forget to export a public thing (hard to miss as build would fail due to missing public item). That being said, pub > pri.

4 Likes

Is the suggestion here a turn away from module type hiding? Seems like a solved problem already?

1 Like

Jumping from interface to implementation and back is not ideal DX even with help from the editors.

But ultimately it’s the only bulletproof way to control visibility. E.g. you can’t do abstract types without it.

3 Likes

I like this, but you can reach for export let here to be an even better on ramp for js developers.

Only thing with this approach is the migration path would be harder IMO

1 Like

Hi all, thanks for all the discussions.

I like this proposal mostly because it is very easy to implement compared with using a keyword like private, and the implementation should be very efficient.

So if we want to get a lightweight private mechanism, this seems to be the most realistic solution, I guess Go adopts this approach might because of similar reasons.

I have lots of to do so this is not a high priority, just to let you know all the tradeoffs.

2 Likes

No. Both module type and explicit private have their use cases

Copying over my thoughts from the other thread:

An explicit decorator or keyword is the best solution though IMO. It’s explicit, obvious, and without footguns.

Ideally I would want everything private by default and sprinkle %%public on bindings I want to expose (like Rust), but I get that this kind of breaking change may not be feasible. Given that, I prefer just having %%private (and fixing any issues that exist with it) instead of adding multiple ways to do something as critical as privacy.

1 Like

Was this proposal abandoned? It would pretty much solve all React Fast Refresh issues, we wouldn’t need interface files just to ensure fast refresh works correctly.

3 Likes