ts.
ts.

Reputation: 10709

scala equivalent of python __getattr__ / __setattr__

Is there scala equivalent of python __getattr__ / __setattr__ (and other __*__ methods?). Some thing built-in or maybe some traits?

Upvotes: 4

Views: 1481

Answers (2)

Debilski
Debilski

Reputation: 67888

For __getattr__ and __setattr__ you’ll have to wait until someone with more insight describes the new Scala 2.10 reflection API. (And of course: it won’t be directly translatable ever. It depends completely on your use case. If you just want a dynamic class, there will be a Dynamic trait in the future; if you just want a tiny bit of that, then designing around pattern matching may be an obvious choice.)

As for the multitude of other __*__ methods in Python:

Global things

  • __call__apply() // pretty much identical in behaviour
  • __metaclass__ // use case dependent:
    • currently class inheritance or trait mixins may be useful
    • in many cases all that metaclass does is instance construction which avoids a call to super(); in Scala super() is always called in the constructor.
  • __repr__, __str__toString()
  • __eq__equals()
  • __init__ // implicitly called in the class body
  • __new__ // not directly existent; depending on use case early initialisation
  • __del__ // missing
  • __nonzero__ // not really, except implicit def toBool[MyType](a: MyType): Boolean = ...

Container Types

  • __len__length, size or whatever is the convention in the container
  • __getitem__apply(i: IndexType) // containers are functions in Scala
  • __setitem__update(i: IndexType, v: ValueType)
  • __delitem__ // no special handling needed; container convention
  • __iter__foreach(block: ValueType => Unit) // with return value: map, flatMap

Notably, apply and update are special in Scala, just as their Python counterparts. They allow for the following Syntax:

val x = collection(elem) // val x = collection.apply(elem)
collection(elem) = y // collection.update(elem, y)

Similarly, just as Python’s __iter__ allows a syntax like (el for el in container) foreach and map make it possible to say for (el <- container) yield el.

Operators

generally no special handling needed as we are allowed to define those directly:

  • __add__, __sub__, … // just define def + (arg: T) or def - (arg: T)

this also includes comparison operators

  • __lt__, __ge__def <(other: T), def <=(other: T)

however, just as in Python, there are some special cases in the compiler for advanced things:

  • __radd__, __rsub__, … // right-associative operators; approx. def +: (arg: T) or def -: (arg: T) (append a :)
  • __iadd__, __isub__, … // modifying operators: def += (arg: T), …

Context manager

  • __enter__, __exit__ // in most cases, a function argument fulfills the same purpose

See also: List of Scala's "magic" functions

Upvotes: 11

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297265

I'm not sure what's the point here. Scala's uniform access principle means "fields" and methods share the same interface -- because, in fact, "fields" in Scala are getters and setters.

In other words, you can replace them like this:

var x: Int = 0

private[this] var _x = 0
def x = _x
def x_=(n: Int) { _x = n }

The getter and setter methods will control access to the private field you declared.

Now, if all you want is a way to provide non-static fields, you have to look at the Dynamic trait. It's experimental up to 2.9.2, but it will be available on 2.10, though behind a flag to warn people that this feature is dangerous (because it introduces dynamic typing, but if you don't think dynamic typing is dangerous, you should be fine).

Upvotes: 2

Related Questions