i am creating a small scala DSL and running into the following problem to which i dont really have a solution. A small conceptual example of what i want to achieve:
(Compute
write "hello"
read 'name
calc()
calc()
write "hello" + 'name
)
the code defining this dsl is roughly this:
Object Compute extends Compute{
...
implicit def str2Message:Message = ...
}
class Compute{
def write(msg:Message):Compute = ...
def read(s:Symbol):Compute = ...
def calc():Compute = { ... }
}
Now the question: how can i get rid of these parenthesis after calc? is it possible? if so, how? just omitting them in the definition does not help because of compilation errors.
ok, i think, i found an acceptable solution... i now achieved this possible syntax
| write "hello"
| read 'name
| calc
| calc
| write "hello " + 'name
using an object named "|", i am able to write nearly the dsl i wanted. normaly, a ";" is needed after calc if its parameterless. The trick here is to accept the DSL-object itself (here, its the "|" on the next line). making this parameter implicit also allows calc as a last statement in this code.
well, looks like it is definitly not possible to have it the way i want, but this is ok too
It's not possible to get rid of the parenthesis, but you can replace it. For example:
object it
class Compute {
def calc(x: it.type):Compute = { ... }
(Compute
write "hello"
read 'name
calc it
calc it
write "hello" + 'name
)
To expand a bit, whenever Scala sees something like this:
object method
non-reserved-word
It assumes it means object.method(non-reserved-word). Conversely, whenever it sees something like this:
object method object
method2 object2
It assumes these are two independent statements, as in object.method(object); method2.object, expecting method2 to be a new object, and object2 a method.
These assumptions are part of Scala grammar: it is meant to be this way on purpose.
First try to remove the parentheses from the definition of calc. Second try to use curly braces around the whole instead of parentheses. Curly braces and parentheses doesn't mean the same and I find that parenthesis works best in single line code (unless using semi-colons). See also What is the formal difference in Scala between braces and parentheses, and when should they be used?
Related
If I remove the parentheses from below to read printFn hc I get an error. I thought in Scala one parameter functions don't need the parens?
case class HelloClass(arg1:String)
object HelloWorld extends App {
var hc = HelloClass("Hello World")
printFn(hc)
def printFn(a1:HelloClass) : Unit = {
println(a1 arg1) /* or a1.arg1 */
}
}
I think you mixed it up with the infix method notation. In Scala you can write either obj.method(argument) or obj method argument.
To apply this to your example, you need the "obj" part of the expression, so if you want to avoid parenthesis, you can write
this printFn hc
See also "When to use parenthesis in Scala infix notation".
I Would like to add something about postfix as another answer covered about infix.Copied from Programming Scala
So, 1 + 2 is the same as 1.+(2), because of the “infix” notation where
we can drop the period and parentheses for single-argument methods.1
Similarly, a method with no arguments can be invoked without the
period. This is called “postfix” notation. However, use of this
postfix convention can sometimes be confusing, so Scala 2.10 made it
an optional feature.
Example for Postfix
1 toString
Example for Infix
private def testMethod(arg1: String): String = {
arg1
}
//this specifies current instance
println(this testMethod "Hello Scala")
I'm trying to decipher somebody else's code. The following appeared in a Scala trait. This isn't its exact content, I flattened out some of the detail to make it more general (it had some extra lines before the closed-curly-bracket incorporating a zipWithIndex method, and some other pattern matching stuff.) My main concern was that I am not familiar with this concept; a value definition that begins with an open-curly-bracket and then a bunch of indented stuff.
val example: ExampleType = {
val anOtherExample = "String"
val yetAnOtherExample = 22
new ExampleType(anOtherExample, yetAnOtherExample)
}
Having experience with C-like languages and/or Java, you may be used to the fact that curly braces {} denote a block of code - i.e. just a set of instructions that will be invoked.
Scala is different on this part, because in Scala almost everything is an expression, i.e. almost everything evaluates to some value and therefore can be assigned to a val, passed as an argument, etc.
Therefore, a block of code in Scala is not just a sequence of instructions, but a valid expression that can be assigned and passed around. Block of code evaluates to the last expression in that block, i.e.
val x: Int = {
doSomething()
doSomethingElse()
42
}
In the above example, x will have 42 assigned as its value.
{
val anotherExample = "String"
val yetAnotherExample = 22
}
This is called block. It is evaluated to its last statement. Here the last statement is an assignment val yetAnotherExample = 22 which is of type Unit in Scala. So your code will not compile if your ExampleType is not the same type as Unit.
Methods are often declared with obvious parameter names, e.g.
def myMethod(s: String, image: BufferedImage, mesh: Mesh) { ... }
Parameter names correspond to parameter types.
1) "s" is often used for String
2) "i" for Int
3) lowercased class name for one word named classes (Mesh -> mesh)
4) lowercased last word from class name for long class names (BufferedImage -> image)
(Of course, it would not be convenient for ALL methods and arguments. Of course, somebody would prefer other rules…)
Scala macros are intended to generate some expressions in code. I would like to write some specific macros to convert to correct Scala expressions something like this:
// "arguments interpolation" style
// like string interpolation
def myMethod s[String, BufferedImage, Mesh]
{ /* code using vars "s", "image", "mesh" */ }
// or even better:
mydef myMethod[String, BufferedImage, Mesh]
{ /* code using vars "s", "image", "mesh" */ }
Is it possible?
Currently it is not possible and probably it will never be. Macros can not introduce their own syntax - they must be represented through valid Scala code (which can be executed at compile time) and, too, they must generate valid Scala code (better say a valid Scala AST).
Both of your shown examples are not valid Scala code, thus Macros can not handle them. Nevertheless, the current nightly build of Macro Paradise includes untyped macros. They allow to write Scala code which is typechecked after they are expanded, this means it is possible to write:
forM({i = 0; i < 10; i += 1}) {
println(i)
}
Notice, that the curly braces inside of the first parameter list are needed because, although the code is not typechecked when one writes it, it must represent a valid Scala AST.
The implementation of this macro looks like this:
def forM(header: _)(body: _) = macro __forM
def __forM(c: Context)(header: c.Tree)(body: c.Tree): c.Tree = {
import c.universe._
header match {
case Block(
List(
Assign(Ident(TermName(name)), Literal(Constant(start))),
Apply(Select(Ident(TermName(name2)), TermName(comparison)), List(Literal(Constant(end))))
),
Apply(Select(Ident(TermName(name3)), TermName(incrementation)), List(Literal(Constant(inc))))
) =>
// here one can generate the behavior of the loop
// but omit full implementation for clarity now ...
}
}
Instead of an already typechecked expression, the macro expects only a tree, that is typechecked after the expansion. The method call itself expects two parameter lists, whose parameter types can be delayed after the expansion phase if one uses an underscore.
Currently there is a little bit of documentation available but because it is extremely beta a lot of things will probably change in future.
With type macros it is possible to write something like this:
object O extends M {
// traverse the body of O to find what you want
}
type M(x: _) = macro __M
def __M(c: Context)(x: c.Tree): c.Tree = {
// omit full implementation for clarity ...
}
This is nice in order to delay the typechecking of the whole body because it allows to to cool things...
Macros that can change Scalas syntax are not planned at the moment and are probably not a good idea. I can't say if they will happen one day only future can tell us this.
Aside from the "why" (no really, why do you want to do that?), the answer is no, because as far as I know macros cannot (in their current state) generate methods or types, only expressions.
I'm following a groovy tutorial and there is a code like this:
def fruit = ["apple", "orange" , "pear"] //list
def likeIt = { String fruit -> println "I like " + fruit + "s" } //closure
fruit.each(likeIt)
Eclipse reports an error at closure definition line:
Line breakpoint:SimpleClosuresTest
[line: 27] The current scope already
contains a variable of the name fruit
# line 27, column 14.
If i omit 'def' from 'def fruit' Eclipse doesn't complaint and code runs fine.
Could someone explain what is going on with the scopes in both cases?
Thanks.
first a general review of a groovy script:
// file: SomeScript.groovy
x = 1
def x = 2
println x
println this.x
is roughly compiled as:
class SomeScript extends groovy.lang.Script {
def x
def run() {
x = 1
def x = 2
println x // 2
println this.x // 1
}
}
in a groovy script (roughly speaking, a file without the class declaration), assigning a value to an undefined variable is interpreted as a field assignment.
your example tries to defines a closure with a parameter named fruit.
if you defined fruit with the def keyword you get an error message because the name is already taken as a local variable, and you can't duplicate a local variable name.
when you leave the def keyword out, you are actually assigning the value to a field of the class generated for the script, and thus the name fruit can be redefined as a local variable.
regarding scopes, it's pretty much like java...
in the example, you can see x is defined first as a field and then as a variable local to the run() method. there's nothing wrong with that and you can access both the variable and the field.
but once you define a local variable, you cannot create duplicates.
edit --
had to add this before anyone gets me wrong: the translation is not exactly like this (thus the "roughly"). Instead of a field you add a value to the binding of the script, quite like args for commandline scripts or request, session or response for groovlets.
but that is much a longer story...
ok if you really want to know just ask again and i'll explain it better
edit 2 --
i just can't leave it like this, if you ever need more info...
every groovy script has a field named binding, an instance of groovy.lang.Binding or one of its a subclasses.
this binding is basically a map, with methods setVariable and setVariable.
when you omit the def keyword when assigning a value in a script you are actually calling the method setVariable, and when you do something like this.x you are calling the getVariable method.
this is actually because class groovy.lang.Script overrides the methods getProperty and setProperty to call those methods first. that's the reason they behave like fields.
you might have also noticed that there is no type associated to those variables... that's because we are dealing with just a Map inside the binding.
standard groovy scrips are created with an instance of a binding with the args set to the array of parameters.
others, like groovy.servlet.ServletBinding define more variables and behavior, like block the assignment of certain variables, or adding a lazy initialization capabilities...
then the real reason behind the error is... if the def keyword is not used, fruits is not a real variable. still, i believe the behavior is somewhat analog to a field.
sorry about all that.
i was not satisfied with my own oversimplification :S
That String fruit shouldn't be having the same name as your def fruit. (you are defining first a list and then a string with the same name)
def likeIt = { String fruit -> println "I like " + fruit + "s" }
In the second case you are defining the type of the variable with def a posteriori, so it works but it is not a good practice as far as I know.
I think that you don't even need to write ->. The groovy manual says that "The -> token is optional and may be omitted if your Closure definition takes fewer than two parameters", which is the case here.
Second line
String fruit
the same variable name 'fruit' is being used again
I don't understand why the following code doesn't compile:
class Abc
{
def b (x : String) = x + "abc"
def a (y : String) =
{
val ls : List[String] = y.lines toList
b (ls.head)
}
}
Main.scala:8: error: type mismatch;
found : java.lang.String
required: Int
b (ls.head)
When I change "y.lines toList" to
y.lines.toList
or even to
y.lines toList;
it does compile.
Perhaps the compiler understands it like
(y.lines).toList(b (ls.head))
or something like that, but I still don't understand the rules.
It's not obvious, and it's a combination of Scala's shortcut syntax and list indexing. If you want a hint, try redefining b to:
def b(x : String) = 0
You'll get some other compiler garbage back, but the error will change. In short, the Scala compiler will let you omit parens and dots for zero- or one-parameter methods, and we know b looks like it's somehow getting chained.. The rub is that Scala also uses parens for list indexing, so toList, which returns an iterator, may take one parameter as the list index. I'm not sure of this part exactly, but it looks like once you start omitting dots, the lexer will become greedy, and when it comes across a method that may take one parameter, will attempt to pass the next statement to it. In this case, that's a string, so it throws a syntax error.
You got it spot on with this:
(y.lines).toList(b (ls.head))
With the only possible correction being:
(y.lines).toList(b).apply(ls.head)
I'm not sure that Scala would decide in this particular case.
The rule, roughly speaking, is object (method parameters)* [method]. The compiler will continue as long as it finds tokens for a valid expression. A ; finishes the expression, and so would a ) or }. If the next line is blank, the expression also ends. If the next line begins with a reserved keyword (val, def, if, etc), the expression would end too.