James Whiteley
James Whiteley

Reputation: 3464

Calling methods with parameters without using parentheses

I am using the following implicit class in order to call a function which would otherwise take parameters without having to write the parameters in brackets:

scala> implicit class Print(string: String) {
     |   def echo: Unit = Console.println(string)
     | }
defined class Print

scala> "Hello world" echo
Hello world

However while this works, I don't really like how it looks and my goal is to get the method call in front of the input variable as I think it reads better.

Is there any simple way, without relying on external libraries, to be able to call a method before supplying the parameters and without needing brackets? Implicit classes are what I've been using so far but that doesn't have to be the final solution.

What I would like to type instead of "Hello world" echo:

scala> echo "Hello world"



Alternatives I have tried:

Requires parentheses

object echo {
  def apply(string: String): Unit = Console.println(string)
}

echo "Hello world" // Error: ';' or newline expected

Doesn't seem to work in my version of Scala

Looks ugly and not what I am looking for

Looks to do basically what my implicit class solution does, and I don't want any external dependencies.



EDIT

This answer has been pointed to as a potential solution, but again it doesn't address my issue as it relies on Dynamic to achieve a solution. As previously mentioned, Dynamic does not solve my problem for a couple of reasons:

If you define a val and try to println that val, it gives you back the val's name and not its value (as pointed out by @metaphori):

object println extends Dynamic {
  def typed[T] = asInstanceOf[T]
  def selectDynamic(name: String) = Console.println(name)
}

val x = "hello"
println x     // prints: x

If I just misunderstood how to implement it then I would appreciate a scalafiddle demonstrating that this solution solves my problem and will happily concede that this question is a duplicate of the previously mentioned answer, but until then I do contest it.

Upvotes: 0

Views: 762

Answers (2)

metaphori
metaphori

Reputation: 2811

You cannot achieve

echo "str"

since Scala is not e.g. Ruby: it syntactically requires that function invocations use parentheses. It is not a matter of semantics or how things are implemented or what techniques are used: here is the parser that complains. The point is that x y is actually interpreted as x.y, which means that y must be a method.

Refer to the Scala Language Specification, section 6.6 Function Applications:

SimpleExpr    ::=  SimpleExpr1 ArgumentExprs
ArgumentExprs ::=  ‘(’ [Exprs] ‘)’
                |  ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’
                |  [nl] BlockExpr
Exprs         ::=  Expr {‘,’ Expr}

I do not like the trick of @hüseyin-zengin since it leverages dynamic method invocations, and also does not work as expected:

val x = "hello"
println x     // prints: x

To partially achieve what you like you need to use infix operator notation

object run { def echo(s: String) = println(s) }

run echo "hello" // OK
run.echo "hello" // error: ';' expected but string literal found.

You may also use a symbol to reduce "typing" overhead (though may be perceived weirdly):

object > { def echo(s: String) = println(s) }

> echo "hello" // OK

Upvotes: 1

Hüseyin Zengin
Hüseyin Zengin

Reputation: 1226

AFAIK only way to do something similar to what you want is extending Dynamic like this:

object println extends Dynamic {
  def typed[T] = asInstanceOf[T]
  def selectDynamic(name: String) = Console.println(name)
}

and using it with:

println `Hello World`

edit: of course you need to enable related features either by adding compiler parameters -language:postfixOps and -language:dynamics or by importing scala.language.dynamics and scala.language.postfixOps

Upvotes: 2

Related Questions