0

I found in Scala: can't write setter without getter? that you can't create a setter without getter:

The interpretation of an assignment to a simple variable x = e depends on the definition of x. If x denotes a mutable variable, then the assignment changes the current value of x to be the result of evaluating the expression e. The type of e is expected to conform to the type of x. If x is a parameterless function defined in some template, and the same template contains a setter function x_= as member, then the assignment x = e is interpreted as the invocation x_=(e ) of that setter function. Analogously, an assignment f.x = e to a parameterless function x is interpreted as the invocation f.x_=(e ). An assignment f(args) = e with a function application to the left of the ‘=’ operator is interpreted as f.update(args, e ) , i.e. the invocation of an update function defined by f .

So it is a design decision to not allow setters without getters. But why? Is it just be harder to implement or is it fundamentally impossible to do?

I do have a valid use case for it, using it as a (somewhat complex) setter, where not using this syntactic sugar would break having the same syntax everywhere in the project.

Community
  • 1
  • 1
Rik Schaaf
  • 1,101
  • 2
  • 11
  • 30
  • Can you explain the situation? Why is it a *problem* to have a getter? – Nathaniel Ford Aug 25 '16 at 00:46
  • @NathanielFord the problem is that it is part of an api, it would confuse the user in thinking that a getter could be used. Situation: an object of class A has a setter that sets a certain value. An object of class B that is in a way 'connected' to the object of class A is able to get this value using its getter with the same name. Think of it like two devices with a wire in between, where one device only has an output, which is the input of the other device: (in class A) out.value = 3.0 and (in class B) println(in.value) – Rik Schaaf Aug 25 '16 at 01:01
  • 1
    @coolcat007: In that case, you probably should use an explicit setter method instead of an assignment. – Bergi Aug 25 '16 at 01:21
  • @coolcat007 What Bergi said. But also note that S.O. is not good at answer 'why is it this way' questions, just 'what can I do about the fact it is this way' questions. In your case, it seems like you should just write your own setter for an internal, hidden value. The 'reason' Scala does things this way is that they want to be able to make assumptions in the compiler that simplify life: paired getters and setters does that. – Nathaniel Ford Aug 25 '16 at 01:25
  • @NathanielFord I think that the way that scala works at the moment, it is indeed best to create an explicit setter,even though in my opinion this looks ugly in the code, as one of the reasons for using Scala is so that I don't have to use the word 'set' in every setter. I was looking through the scala compiler source code, but I couldn't find where the _= conversion was implemented. Is it somewhere in the nsc.transform package or am I looking in the wrong location? – Rik Schaaf Aug 25 '16 at 02:24
  • @coolcat007 the conversion is triggered when typechecking the assignment, see `typedAssign` and `normalTypedApply`. See my answer that it's not mere syntax rewrite, if that's a useful distinction. – som-snytt Aug 25 '16 at 15:57
  • @NathanielFord agree with you that the question doesn't fit the forum. – som-snytt Aug 25 '16 at 16:01

1 Answers1

1

You might try this to exclude the accessor from your API:

scala> class C { def c_=(i: Int) = println(i) ; private def c: Int = ??? }
defined class C

scala> val c = new C
c: C = C@289fdb08

scala> c.c = 42
<console>:14: error: method c in class C cannot be accessed in C
val $ires0 = c.c
               ^
<console>:12: error: method c in class C cannot be accessed in C
       c.c = 42
         ^

scala> def f = { c.c = 42 ; 0 }
<console>:12: error: method c in class C cannot be accessed in C
       def f = { c.c = 42 ; 0 }
                   ^

In the first error, the REPL is trying to report the value by using the accessor.

This notion of paired accessor and mutator is called the universal access principle, so that accessed member looks like a property.

The expression c.c must type-check before further desugaring. Otherwise, the transform (to an invocation of c.c_=) must be purely syntactic.

For example, an implicit conversion that supplies an extension method c_= could come into play.

som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • I am a little bit confused by the last two paragraphs of your answer. What exactly do you mean? – Rik Schaaf Aug 25 '16 at 02:26
  • Just that `c.c` must mean something on its own. If you said that `c.c =` just means `c.c_=` then an implicit conversion could add the `c_=` mutator. That's a long way from having a simple property. – som-snytt Aug 25 '16 at 02:44
  • Consider http://pastebin.com/yxsmumG3 (yes, I know, something something salt...) it might not be a "simple" property, but the usage is quite clear and it can be seen that the getter `password` will never be used, while `password_=` is half of the core part of this example. I could rename `password_=` to `setPassword` and call that method explicitly, but then we are back were we were when using Good Old Java. Leaving in the password getter would confuse anyone who uses the API. – Rik Schaaf Aug 25 '16 at 03:01
  • I guess my argument about what is a `property` was not persuasive. But if the question is, what are you expected to do instead, then the ecosystem is rife with assignment operators, which are ops ending in `=`. So you could `password ~= "secret"` where the tilde reminds you that mumbo-jumbo hash is applied before setting the value. See the various ops in sbt, `<++=` etc at http://www.scala-sbt.org/0.13.12/api/index.html#index.index-_ – som-snytt Aug 25 '16 at 03:58
  • OK, never mind my last comment: https://twitter.com/eed3si9n/status/769029653700968448 – som-snytt Aug 26 '16 at 04:48