Thursday, April 28, 2011

Do methods ending with _! have a special meaning in Scala?

Do methods ending with _! such as delete_! or i_is_! have a special meaning? Are they "just names"? Do they follow some convention? There's even bulkDelete_!!. (The specific context is Lift if it makes a difference.)

From stackoverflow
  • There are no special meanings to the ! in Scala names. In the family of Lisp-based languages, ! is often used to indicate that a function is has side-effects, and that looks to be the convention here.

    retronym : Another similar convention is to use to use zero parameter lists for side-effect free functions, and one empty parameter list for others. e.g. `gun.model` vs `gun.fire()`
    OscarRyz : Ruby uses `!` for *side effects* also
  • I'm not sure what the convention is for using _! and _!! in Lift, but here's a bit of background.

    Any alphanumeric identifier can have _ and a list of symbols added and still be parsed as a single identifier. For example:

    scala> class Example_!@%*!
    defined class Example_$bang$at$percent$times$bang
    

    (In fact, you can parse almost anything as an identifier if you surround it with backticks--and this is what you do if a Java class uses a Scala reserved word, for example. Or if you want spaces in your identifiers.)

    The compiler only recognizes one symbolic ending specially, however. If there is a method that looks like a getter, then getter_= will be interpreted as a setter. (Whether you actually use it as a setter is up to you; it will have the semantics of a setter, anyway.) So

    scala> class Q { def q = "Hi"; def q_=(s: String) { println(s.reverse) } }
    defined class Q
    
    scala> val q = new Q
    q: Q = Q@b5c12e
    
    scala> q.q
    res0: java.lang.String = Hi
    
    scala> q.q = "Could use this to set something"
    gnihtemos tes ot siht esu dluoC
    

    In addition, the compiler reverses the order of caller and callee in any method that ends in :. This is most often seen in lists: newElement :: existingList is actually a call to existingList.::(newElement). So, for example:

    scala> object Caps { def to_:(s: String) = s.toUpperCase }
    defined module Caps
    
    scala> "Example" to_: Caps
    res40: java.lang.String = EXAMPLE
    

    Any other usage of _ + symbols is convention.

    aioobe : Wow. Great lecture. I knew almost none of this. Thanks!
    retronym : `_` is used to separate groups of word characters from symbol characters. So `foo_!!_bar` is a legal identifier. If you don't want to follow this rule, or need to use a reserved word, you can also enclose it in backticks. This is useful for calling java methods named `type`, for example.
    Rex Kerr : @retronym - Good point about backticks; I'll add that. Try typing `val foo_!!_bar = 0` into the REPL, though....
    retronym : Oh wow, my mental parser is out of sync with the spec. Please ignore. Identifers are basically `\w[\w\d]*(_([:opchar:]*))`
    OscarRyz : Mhh, So, I understand that it is not possible to type for instance `def sort!( ... ` but you would have to use: `def sort_!(...` is that correct?
    Rex Kerr : @S-mSO - That's right. `def sort!()` is invalid. `def sort_!()` is fine.
    aioobe : Ah, that's good to know.
    PhiLho : @retronym: more like `\w[\w\d]*(_([:opchar:]*))?|[:opchar:]+` I think (including $ but this one is reserved). Also I just found out that // and /* cannot be operators...
  • Strangely unmentioned thus far (though not particularly relevant to your question) is unary_! which is treated specially.

    scala> class A { def unary_! = 5 }
    defined class A
    
    scala> !(new A)
    res0: Int = 5
    

0 comments:

Post a Comment