0

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:

  • Object with apply method

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:

  • It behaves funnily

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
  • The specific example linked to did not work when I tried to recreate it - it still gave the ';' or newline expected error

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.

James Whiteley
  • 3,363
  • 1
  • 19
  • 46
  • Possible duplicate of [Object methods call without parentheses](https://stackoverflow.com/questions/22542159/object-methods-call-without-parentheses) – metaphori Jun 13 '18 at 16:51
  • I disagree - edited the post to explain – James Whiteley Jun 13 '18 at 17:22
  • No: the dynamic trick used in the other discussion does not suffer of the issue of @hüseyin-zengin; nevertheless, it has another inconvenience (related to termination of an instruction). The [other answer](https://stackoverflow.com/a/22544054/2250712) to the other discussion basically is the same as mine below. [This discussions](https://stackoverflow.com/questions/3617491/why-cant-i-write-println-hello-world-in-scala/3617550#3617550) is also somewhat related. The "correct answer" to the question is basically the point that `x y` actually is `x.y`.. – metaphori Jun 13 '18 at 17:27
  • I had read both of those before asking my question, and while they are related I don't believe that they ask the same question - ie, "Is this possible without the use of prepending an object declaration, external dependencies or the Dynamic trait (as I have already tried this)?". It seems that the answer is "No", as you rightly answered - at least with the current version of Scala. – James Whiteley Jun 13 '18 at 17:41

2 Answers2

2

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

Hüseyin Zengin
  • 1,216
  • 11
  • 23
  • This misbehaves when you do something like `val x = "hello"; println x`, as @metaphori points out. I am also curious about the `typed` function though... – James Whiteley Jun 13 '18 at 16:44
1

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
metaphori
  • 2,681
  • 1
  • 21
  • 32
  • I wasn't aware that it specified in the Specification that what I want isn't possible. How annoying that infix notation doesn't extend to something like `echo "hello"` without the object specified before it. For now, I guess I'm stuck with my backwards-Ruby `"hello" echo` then! – James Whiteley Jun 13 '18 at 16:42