Pharo Smalltalk Method Execution - methods

I have a few test cases that I need to write a method for, and how they execute the method is like this:
Planets with: aString , anotherString
Where "Planets" is a class and "with:" is a class method. But my confusion is in the way that arguments are given, because I was under the impression that methods with multiple arguments get executed like "methodName: arg1 Arg2: arg2", but in here the two arguments are separated by comma. Can somebody explain this to me please?

It has to do with the order of precedence for messages. Unary messages get handled first, then binary messages, and finally keyword messages.
Unary messages have no arguments (new, sqrt, isPrime)
Binary messages go between two objects (like a + or in your case the ,).
Keyword messages end in a colon (like with:) and sometimes there is more than one (like to: do:)
The binary message , (concatenate two strings) is processed first because it has a higher precedence. Then the keyword message with: is processed after because it has a lower precedence. Messages inside of parentheses automatically get the highest precedence and are evaluated first. When there is a "tie" (multiple messages have the same precedence), they are evaluated left to right.
One weird thing about Smalltalk is that + - * / all have the same binary message precedence. So 8 + 2 * 4 evaluates to 40 not 16 like you might expect.

Most likely, the class method #with: receives a String as its only argument. This means that #with: is a keyword message with arity 1. In the expression
Planets with: aString , anotherString
there are two messages: (1) the message with selector #with: and (2) the message with selector #,. The latter has a receiver aString and an argument anotherString. This is a binary message with arity 1 too.
In fact, one could equally write
Planets with: (aString , anotherString)
to emphasize the role of argument played by the parenthesized expression. We usually don't do that because precedence rules make it unnecessary.
Now note that in the declaration of the method with selector#with: you would have
Planets class >> #with: aString
"some code here"
But one thing is the declaration of a method and another its invocation, in your case
Plantes with: aString , anotherString
is an expression aimed at sending the message #with: to Planets with an argument that happens to be the concatenation of two strings.
In sum, when you declare/define the method the argument is aString, but when you invoke it (i.e., when you send the message) the argument is anything that evaluates to a String.
As a side note I would indicate that Planets isn't a good name for a class. In fact, class names are usually in singular, as they represent a concept, not a collection of instances of said concept.

Related

Trying to understand this ruby syntax

I am new to ruby and lots of things are confusing me. I believe this specific one is from Sorbet which is some type checking library? not sure. This specific piece of code is right before a method declaration
sig { params(order: T::Hash[
String, T.any(
T.nilable(String), T::Hash[
String, T.any(
Integer, T.nilable(String)
)
]
)
]).returns(Types::Order) }
def self.build_prescription(prescription)
# method implementation
The order object is a json object coming from REST API. Can someone explain what this nesting thing is going on.
This is indeed a Sorbet signature. You can read more about Sorbet in their official documentation
The signature itself in this case is just describing the shape of the parameters and return type of the build_prescription method.
Slightly reformatting to make it easier to annotate:
sig { # A ruby method added by Sorbet to indicate that the signature is starting.
params( # Start to declare the parameters that the method takes
order: T::Hash[ # First param. In this case, it's a Hash...
String, # ... where they key is a String ...
T.any( # ... and the value can be either: ...
T.nilable(String), ... # a nilable String
T::Hash[ # or a Hash ...
String, # ... where the key is a String...
T.any(Integer, T.nilable(String)) # ... and the value is either an Integer or nilable string String
]
)
])
.returns(Types::Order) # Declaration of what the method returns
}
def self.build_prescription(prescription) # the regular Ruby method declaration
Note, though, that this will fail a Sorbet validation, as the signature declares the parameter as order, while the method declares it as prescription. Those two names should match.
There's a way to re-write this signature to make it a bit nicer to read/understand
sig do
params(
prescription: T::Hash[
String,
T.nilable(
T.any(
String,
T::Hash[String, T.nilable(T.any(Integer, String)]
)
)
])
.returns(Types::Order) # Declaration of what the method returns
}
def self.build_prescription(prescription)
Note that I'm moving the T.nilables out one level, as T.any(Integer, T.nilable(String)) means that same as T.nilable(T.any(Integer, String)) but it's more immediately obvious for a reader that the value can be nil
Since you are specifically asking about syntax, not semantics, I will answer your question about syntax.
What you see here, is called a message send. (In other programming languages like Java or C#, it might be called a method call.) More precisely, it is a message send with an implicit receiver.
A message is always sent to a specific receiver (just like a message in the real world). The general syntax of a message send looks like this:
foo.bar(baz, quux: 23) {|garple| glorp(garple) }
Here,
foo is the receiver, i.e. the object that receives the message. Note that foo can of course be any arbitrary Ruby expression, e.g. (2 + 3).to_s.
bar is the message selector, or simply message. It tells the receiver object what to do.
The parentheses after the message selector contain the argument list. Here, we have one positional argument, which is the expression baz (which could be either a local variable or another message send, more on that later), and one keyword argument which is the keyword quux with the value 23. (Again, the value can be any arbitrary Ruby expression.) Note: there a couple of other types of arguments as well in addition to positional arguments and keyword arguments, namely splat arguments and an optional explicit block argument.
After the argument list comes the literal block argument. Every message send in Ruby can have a literal block argument … it is up to the method that gets invoked to ignore it, use it, or do whatever it wants with it.
A block is a lightweight piece of executable code, and so, just like methods, it has a parameter list and a body. The parameter list is delimited by | pipe symbols – in this case, there is only one positional parameter named garple, but it can have all the same kinds of parameters methods can have, plus block-local variables. And the body, of course, can contain arbitrary Ruby expressions.
Now, the important thing here is that a lot of those elements are optional:
You can leave out the parentheses: foo.bar(baz, quux: 23) is the same as foo.bar baz, quux: 23, which also implies that foo.bar() is the same as foo.bar.
You can leave out the explicit receiver, in which case the implicit receiver is self, i.e. self.foo(bar, baz: 23) is the same as foo(bar, baz: 23), which is of course then the same as foo bar, baz: 23.
If you put the two together, that means that e.g. self.foo() is the same as foo, which I was alluding to earlier: if you just foo on its own without context, you don't actually know whether it is local variable or a message send. Only if you see either a receiver or an argument (or both), can you be sure that it is a message send, and only if you see an assignment in the same scope can be sure that it is a variable. If you see neither of those things it could be either.
You can leave out the block parameter list of you're not using it, and you can leave out the block altogether as well.
So let's dissect the syntax of what you are seeing here. The first layer is
sig {
# stuff
}
We know that this is a message send and not a local variable, because there is a literal block argument, and variables don't take arguments, only message sends do.
So, this is sending the message sig to the implicit receiver self (which in a module definition body is just the module itself), and passes a literal block as the only argument.
The block has no parameter list, only a body. The content of the body is
params(
# stuff
).returns(Types::Order)
Again, we know that params is a message send because it takes an argument. So, this is sending the message params to the implicit receiver self (which is here still the module itself, because blocks lexically capture self, although that is part of the language semantics and you asked strictly about syntax). It also passes one argument to the message send, which we will look at later.
Then we have another message send. How do we know that? Well, it takes an argument and has a receiver. We are sending the message returns to the object that was returned by the params message send, passing the expression Types::Order as the only positional argument.
Types::Order, in turn, is a constant reference (Types), the namespace resolution operator (::), followed by another constant reference (Order).
Next, let's look at the argument to params:
params(order: T::Hash[
# stuff
])
Here we have a keyword argument order whose value is the expression T::Hash[ … ]. T::Hash is of course again a constant reference, the namespace resolution operator, and another constant reference.
So, what is []? Actually, that is just another message send. Ruby has syntacic sugar for a limited, fixed, list of special messages. Some examples:
foo.call(bar) is the same as foo.(bar).
foo.+(bar) is the same as foo + bar. (And similar for *, **, /, -, <<, >>, |, &, ==, ===, =~, !=, !==, !~, and a couple of others I am probably forgetting.)
foo.+# is the same as +foo. (And similar for -#.)
foo.! is the same as !foo. (And similar for ~.)
self.`("Hello") is the same as `Hello`, which is somewhat obscure.
foo.[](bar, baz) is the same as foo[bar, baz].
foo.[]=(bar, baz, quux) is the same as foo[bar, baz] = quux.
So, this is simply sending the message [] to the result of dereferencing the constant Hash within the namespace of the object obtained by dereferencing the constant T, and passing two positional arguments.
The first positional argument is String, which is again a constant reference. The second positional argument is the expression T.any( … ), which is a constant reference to the constant T, and then sending the message any to the object referenced by that constant, passing two positional arguments.
The first argument is the expression T.nilable(String), which is dereferencing the constant T, sending the message nilable to the result of dereferencing the constant T, passing a single positional argument, which is the result of dereferencing the constant String.
The second argument is the expression T::Hash[ … ] … and I am going to stop here, because there is really nothing more to explain here. There's constants, message sends, and arguments, and we've seen all of those multiple times before.
So, to summarize, as to your question about syntax: the syntax elements we are seeing here are
message sends
arguments
constants
the namespace resolution operator (which is actually not really a separate syntax element, but simply one of many operators)
and a block literal

What is the exact difference between the expression and the statement in programming [duplicate]

In Python, what is the difference between expressions and statements?
Expressions only contain identifiers, literals and operators, where operators include arithmetic and boolean operators, the function call operator () the subscription operator [] and similar, and can be reduced to some kind of "value", which can be any Python object. Examples:
3 + 5
map(lambda x: x*x, range(10))
[a.x for a in some_iterable]
yield 7
Statements (see 1, 2), on the other hand, are everything that can make up a line (or several lines) of Python code. Note that expressions are statements as well. Examples:
# all the above expressions
print 42
if x: do_y()
return
a = 7
Expression -- from the New Oxford American Dictionary:
expression: Mathematics a collection
of symbols that jointly express a
quantity : the expression for the
circumference of a circle is 2πr.
In gross general terms: Expressions produce at least one value.
In Python, expressions are covered extensively in the Python Language Reference In general, expressions in Python are composed of a syntactically legal combination of Atoms, Primaries and Operators.
Python expressions from Wikipedia
Examples of expressions:
Literals and syntactically correct combinations with Operators and built-in functions or the call of a user-written functions:
>>> 23
23
>>> 23l
23L
>>> range(4)
[0, 1, 2, 3]
>>> 2L*bin(2)
'0b100b10'
>>> def func(a): # Statement, just part of the example...
... return a*a # Statement...
...
>>> func(3)*4
36
>>> func(5) is func(a=5)
True
Statement from Wikipedia:
In computer programming a statement
can be thought of as the smallest
standalone element of an imperative
programming language. A program is
formed by a sequence of one or more
statements. A statement will have
internal components (e.g.,
expressions).
Python statements from Wikipedia
In gross general terms: Statements Do Something and are often composed of expressions (or other statements)
The Python Language Reference covers Simple Statements and Compound Statements extensively.
The distinction of "Statements do something" and "expressions produce a value" distinction can become blurry however:
List Comprehensions are considered "Expressions" but they have looping constructs and therfore also Do Something.
The if is usually a statement, such as if x<0: x=0 but you can also have a conditional expression like x=0 if x<0 else 1 that are expressions. In other languages, like C, this form is called an operator like this x=x<0?0:1;
You can write you own Expressions by writing a function. def func(a): return a*a is an expression when used but made up of statements when defined.
An expression that returns None is a procedure in Python: def proc(): pass Syntactically, you can use proc() as an expression, but that is probably a bug...
Python is a bit more strict than say C is on the differences between an Expression and Statement. In C, any expression is a legal statement. You can have func(x=2); Is that an Expression or Statement? (Answer: Expression used as a Statement with a side-effect.) The assignment statement of x=2 inside of the function call of func(x=2) in Python sets the named argument a to 2 only in the call to func and is more limited than the C example.
Though this isn't related to Python:
An expression evaluates to a value.
A statement does something.
>>> x + 2 # an expression
>>> x = 1 # a statement
>>> y = x + 1 # a statement
>>> print y # a statement (in 2.x)
2
An expression is something that can be reduced to a value, for example "1+3" is an expression, but "foo = 1+3" is not.
It's easy to check:
print(foo = 1+3)
If it doesn't work, it's a statement, if it does, it's an expression.
Another statement could be:
class Foo(Bar): pass
as it cannot be reduced to a value.
Statements represent an action or command e.g print statements, assignment statements.
print 'hello', x = 1
Expression is a combination of variables, operations and values that yields a result value.
5 * 5 # yields 25
Lastly, expression statements
print 5*5
An expression is something, while a statement does something.
An expression is a statement as well, but it must have a return.
>>> 2 * 2         #expression
>>> print(2 * 2)     #statement
PS:The interpreter always prints out the values of all expressions.
An expression is a statement that returns a value. So if it can appear on the right side of an assignment, or as a parameter to a method call, it is an expression.
Some code can be both an expression or a statement, depending on the context. The language may have a means to differentiate between the two when they are ambiguous.
STATEMENT:
A Statement is a action or a command that does something. Ex: If-Else,Loops..etc
val a: Int = 5
If(a>5) print("Hey!") else print("Hi!")
EXPRESSION:
A Expression is a combination of values, operators and literals which yields something.
val a: Int = 5 + 5 #yields 10
Expressions always evaluate to a value, statements don't.
e.g.
variable declaration and assignment are statements because they do not return a value
const list = [1,2,3];
Here we have two operands - a variable 'sum' on the left and an expression on the right.
The whole thing is a statement, but the bit on the right is an expression as that piece of code returns a value.
const sum = list.reduce((a, b)=> a+ b, 0);
Function calls, arithmetic and boolean operations are good examples of expressions.
Expressions are often part of a statement.
The distinction between the two is often required to indicate whether we require a pice of code to return a value.
References
Expressions and statements
2.3 Expressions and statements - thinkpython2 by Allen B. Downey
2.10. Statements and Expressions - How to Think like a Computer Scientist by Paul Resnick and Brad Miller
An expression is a combination of values, variables, and operators. A value all by itself is
considered an expression, and so is a variable, so the following are all legal expressions:
>>> 42
42
>>> n
17
>>> n + 25
42
When you type an expression at the prompt, the interpreter evaluates it, which means that
it finds the value of the expression. In this example, n has the value 17 and n + 25 has the
value 42.
A statement is a unit of code that has an effect, like creating a variable or displaying a
value.
>>> n = 17
>>> print(n)
The first line is an assignment statement that gives a value to n. The second line is a print
statement that displays the value of n.
When you type a statement, the interpreter executes it, which means that it does whatever
the statement says. In general, statements don’t have values.
An expression translates to a value.
A statement consumes a value* to produce a result**.
*That includes an empty value, like: print() or pop().
**This result can be any action that changes something; e.g. changes the memory ( x = 1) or changes something on the screen ( print("x") ).
A few notes:
Since a statement can return a result, it can be part of an expression.
An expression can be part of another expression.
Statements before could change the state of our Python program: create or update variables, define function, etc.
And expressions just return some value can't change the global state or local state in a function.
But now we got :=, it's an alien!
Expressions:
Expressions are formed by combining objects and operators.
An expression has a value, which has a type.
Syntax for a simple expression:<object><operator><object>
2.0 + 3 is an expression which evaluates to 5.0 and has a type float associated with it.
Statements
Statements are composed of expression(s). It can span multiple lines.
A statement contains a keyword.
An expression does not contain a keyword.
print "hello" is statement, because print is a keyword.
"hello" is an expression, but list compression is against this.
The following is an expression statement, and it is true without list comprehension:
(x*2 for x in range(10))
Python calls expressions "expression statements", so the question is perhaps not fully formed.
A statement consists of pretty much anything you can do in Python: calculating a value, assigning a value, deleting a variable, printing a value, returning from a function, raising an exception, etc. The full list is here: http://docs.python.org/reference/simple_stmts.html#
An expression statement is limited to calling functions (e.g.,
math.cos(theta)"), operators ( e.g., "2+3"), etc. to produce a value.

Multiplying string by integer vs integer by string in ruby

I was playing around in irb, and noticed one cannot do
5 * "Hello".
Error
String can't be coerced into Fixnum
However "Hello"*5 provided "HelloHelloHelloHelloHello" as expected.
What is the exact reason for this? I've been looking around in the doc's and could not find the exact reason for this behavior. Is this something the designers of ruby decided?
Basically, you are asking "why is multiplication not commutative"? There are two possible answers for this. Or rather one answer with two layers.
The basic principle of OO is that everything happens as the result of one object sending a message to another object and that object responding to that message. This "messaging" metaphor is very important, because it explains a lot of things in OO. For example, if you send someone a message, all you can observe is what their response is. You don't know, and have no idea of finding out, what they did to come up with that response. They could have just handed out a pre-recorded response (reference an instance variable). They could have worked hard to construct a response (execute a method). They could have handed the message off to someone else (delegation). Or, they just don't understand the message you are sending them (NoMethodError).
Note that this means that the receiver of the message is in total control. The receiver can respond in any way it wishes. This makes message sending inherently non-commutative. Sending message foo to a passing b as an argument is fundamentally different from sending message foo to b passing a as an argument. In one case, it is a and only a that decides how to respond to the message, in the other case it is b and only b.
Making this commutative requires explicit cooperation between a and b. They must agree on a common protocol and adhere to that protocol.
In Ruby, binary operators are simply message sends to the left operand. So, it is solely the left operand that decides what to do.
So, in
'Hello' * 5
the message * is sent to the receiver 'Hello' with the argument 5. In fact, you can alternately write it like this if you want, which makes this fact more obvious:
'Hello'.*(5)
'Hello' gets to decide how it responds to that message.
Whereas in
5 * 'Hello'
it is 5 which gets to decide.
So, the first layer of the answer is: Message sending in OO is inherently non-commutative, there is no expectation of commutativity anyway.
But, now the question becomes, why don't we design in some commutativity? For example, one possible way would be to interpret binary operators not as message sends to one of the operands but instead message sends to some third object. E.g., we could interpret
5 * 'Hello'
as
*(5, 'Hello')
and
'Hello' * 5
as
*('Hello', 5)
i.e. as message sends to self. Now, the receiver is the same in both cases and the receiver can arrange for itself to treat the two cases identically and thus make * commutative.
Another, similar possibility would be to use some sort of shared context object, e.g. make
5 * 'Hello'
equivalent to
Operators.*(5, 'Hello')
In fact, in mathematics, the meaning of a symbol is often dependent on context, e.g. in ℤ, 2 / 3 is undefined, in ℚ, it is 2/3, and in IEEE754, it is something close to, but not exactly identical to 0.333…. Or, in ℤ, 2 * 3 is 6, but in ℤ|5, 2 * 3 is 1.
So, it would certainly make sense to do this. Alas, it isn't done.
Another possibility would be to have the two operands cooperate using a standard protocol. In fact, for arithmetic operations on Numerics, there actually is such a protocol! If a receiver doesn't know what to do with an operand, it can ask that operand to coerce itself, the receiver, or both to something the receiver does know how to handle.
Basically, the protocol goes like this:
you call 5 * 'Hello'
5 doesn't know how to handle 'Hello', so it asks 'Hello' for a coercion. …
… 5 calls 'Hello'.coerce(5)
'Hello' responds with a pair of objects [a, b] (as an Array) such that a * b has the desired result
5 calls a * b
One common trick is to simply implement coerce to flip the operands, so that when 5 retries the operation, 'Hello' will be the receiver:
class String
def coerce(other)
[self, other]
end
end
5 * 'Hello'
#=> 'HelloHelloHelloHelloHello'
Okay, OO is inherently non-commutative, but we can make it commutative using cooperation, so why isn't it done? I must admit, I don't have a clear-cut answer to this question, but I can offer two educated guesses:
coerce is specifically intended for numeric coercion in arithmetic operations. (Note the protocol is defined in Numeric.) A string is not a number, nor is string concatenation an arithmetic operation.
We just don't expect * to be commutative with wildly different types such as Integer and String.
Of course, just for fun, we can actually observe that there is a certain symmetry between Integers and Strings. In fact, you can implement a common version of Integer#* for both String and Integer arguments, and you will see that the only difference is in what we choose as the "zero" element:
class Integer
def *(other)
zero = case other
when Integer then 0
when String then ''
when Array then []
end
times.inject(zero) {|acc, _| acc + other }
end
end
5 * 6
#=> 30
5 * 'six'
#=> 'sixsixsixsixsix'
5 * [:six]
#=> [:six, :six, :six, :six, :six, :six]
The reason for this is, of course, that the set of strings with the concatenation operation and the empty string as the identity element form a monoid, just like arrays with concatenation and the empty array and just like integers with addition and zero. Since all three are monoids, and our "multiplication as repeated addition" only requires monoid operations and laws, it will work for all monoids.
Note: Python has an interesting twist on this double-dispatch idea. Just like in Ruby, if you write
a * b
Python will re-write that into a message send:
a.__mul__(b)
However, if a can't handle the operation, instead of cooperating with b, it cooperates with Python by returning NotImplemented. Now, Python will try with b, but with a slight twist: it will call
b.__rmul__(a)
This allows b to know that it was on the right side of the operator. It doesn't matter much for multiplication (because multiplication is (usually but not always, see e.g. matrix multiplication) commutative), but remember that operator symbols are distinct from their operations. So, the same operator symbol can be used for operations that are commutative and ones that are non-commutative. Example: + is used in Ruby for addition (2 + 3 == 3 + 2) and also for concatenation ('Hello' + 'World' != 'World' + 'Hello'). So, it is actually advantageous for an object to know whether it was the right or left operand.
This is because that operators are also methods(Well there are exceptions as Cary has listed in the comments which I wasn't aware of).
For example
array << 4 == array.<<4
array[2] == array.[](2)
array[2] ='x' == array.[] =(2,'x')
In your example:
5 * "Hello" => 5.*("Hello")
Meanwhile
"hello" *5 => 5.*("hello")
An integer cannot take that method with a string param
If you ever dabble around in python try 5*hello and hello*5, both work. Pretty interesting that ruby has this feature to be honest.
Well, as Muntasir Alam has already told that Fixnum does not has a method named * which takes a string as argument. So, 5*"Hello" produces that error.But, to have fun we can actually achieve 5*"Hello" this by adding that missing method to the Fixnum class.
class Fixnum # open the class
def * str # Override the *() method
if str.is_a? String # If argument is String
temp = ""
self.times do
temp << str
end
temp
else # If the argument is not String
mul = 0
self.times do
mul += str
end
mul
end
end
end
now
puts 5*"Hello" #=> HelloHelloHelloHelloHello
puts 4*5 #=> 20
puts 5*10.4 #=> 52.0
Well, that was just to show that the opposite is also possible. But that will bring a lot of overhead. I think we should avoid that at all cost.

Why an empty string seems emitted instead of a custom node, sometimes, in a Treetop grammar?

I'd like your advice concerning a recurring problem concerning my usage of Treetop,that I cannot fix...from time to time. I'm probably missing something.
I suspect many of you have the right idiom or habits to solve that.
I generally use Treetop like the following :
I define my grammar in a .tt file
I modify it to emit custom parse tree objets
(that inherit Treetop::Runtime::SyntaxNode). These classes are
defined in a "parsetree.rb" file.
these custom objects have a
to_ast method to turn them recursively into "pure"
Treetop-independent classes (that constitute my final AST). I have
two separate modules (ParseTree & AST) for that.
However, I hit a classical error message, that I cannot generally fix :
parsetree.rb:380:in `to_ast': undefined method `to_ast' for SyntaxNode
offset=149, "":Treetop::Runtime::SyntaxNode (NoMethodError)
I am puzzled here because an empty string "" seems to be emitted instead of one of my custom nodes.
In this example, on this line 380 I have the following code ( it is about a finite state machine)
# in parsetree.rb
class Next < Tree
def to_ast
ret=Ldl::Ast::Next.new
ret.name=ns.to_ast
if cond
ret.condition=cond.c.to_ast
end
ret.actions=acts.to_ast # <==== line 380
ret
end
end
class NextActions < Tree
def to_ast
eqs.elements.collect{|eq| eq.to_ast}
end
end
And my piece of grammar concerned by the error is :
rule nextstate
space? 'next' space ns:identifier space? cond:('?' space? c:expression)? space
acts:next_actions? <Ldl::ParseTree::Next>
end
rule next_actions
space? eqs:equation+ space 'end' space <Ldl::ParseTree::NextActions>
end
Your problem is with the behaviour of optional expressions.
The acts:next_actions is optional. If this optional element is unmatched in the input, you don't get a NextActions node but an epsilon. You should detect that by saying something like:
ret.actions = acts.empty? ? [] : acts.to_ast
The same problem may occur because the sequence named by the tag cond: is optional. If this sequence doesn't exist in the input, then it has no content "c". In that case "cond" will still be defined and your "if" statement will be true, but cond.c.to_ast will fail.
Short answer: When you use an optional expression, you should tag it and test the tag for empty? before trying to use the content.

What are the precise rules for when you can omit parenthesis, dots, braces, = (functions), etc.?

What are the precise rules for when you can omit (omit) parentheses, dots, braces, = (functions), etc.?
For example,
(service.findAllPresentations.get.first.votes.size) must be equalTo(2).
service is my object
def findAllPresentations: Option[List[Presentation]]
votes returns List[Vote]
must and be are both functions of specs
Why can't I go:
(service findAllPresentations get first votes size) must be equalTo(2)
?
The compiler error is:
"RestServicesSpecTest.this.service.findAllPresentations
of type
Option[List[com.sharca.Presentation]]
does not take parameters"
Why does it think I'm trying to pass in a parameter? Why must I use dots for every method call?
Why must (service.findAllPresentations get first votes size) be equalTo(2) result in:
"not found: value first"
Yet, the "must be equalTo 2" of
(service.findAllPresentations.get.first.votes.size) must be equalTo 2, that is, method chaining works fine? - object chain chain chain param.
I've looked through the Scala book and website and can't really find a comprehensive explanation.
Is it in fact, as Rob H explains in Stack Overflow question Which characters can I omit in Scala?, that the only valid use-case for omitting the '.' is for "operand operator operand" style operations, and not for method chaining?
You seem to have stumbled upon the answer. Anyway, I'll try to make it clear.
You can omit dot when using the prefix, infix and postfix notations -- the so called operator notation. While using the operator notation, and only then, you can omit the parenthesis if there is less than two parameters passed to the method.
Now, the operator notation is a notation for method-call, which means it can't be used in the absence of the object which is being called.
I'll briefly detail the notations.
Prefix:
Only ~, !, + and - can be used in prefix notation. This is the notation you are using when you write !flag or val liability = -debt.
Infix:
That's the notation where the method appears between an object and it's parameters. The arithmetic operators all fit here.
Postfix (also suffix):
That notation is used when the method follows an object and receives no parameters. For example, you can write list tail, and that's postfix notation.
You can chain infix notation calls without problem, as long as no method is curried. For example, I like to use the following style:
(list
filter (...)
map (...)
mkString ", "
)
That's the same thing as:
list filter (...) map (...) mkString ", "
Now, why am I using parenthesis here, if filter and map take a single parameter? It's because I'm passing anonymous functions to them. I can't mix anonymous functions definitions with infix style because I need a boundary for the end of my anonymous function. Also, the parameter definition of the anonymous function might be interpreted as the last parameter to the infix method.
You can use infix with multiple parameters:
string substring (start, end) map (_ toInt) mkString ("<", ", ", ">")
Curried functions are hard to use with infix notation. The folding functions are a clear example of that:
(0 /: list) ((cnt, string) => cnt + string.size)
(list foldLeft 0) ((cnt, string) => cnt + string.size)
You need to use parenthesis outside the infix call. I'm not sure the exact rules at play here.
Now, let's talk about postfix. Postfix can be hard to use, because it can never be used anywhere except the end of an expression. For example, you can't do the following:
list tail map (...)
Because tail does not appear at the end of the expression. You can't do this either:
list tail length
You could use infix notation by using parenthesis to mark end of expressions:
(list tail) map (...)
(list tail) length
Note that postfix notation is discouraged because it may be unsafe.
I hope this has cleared all the doubts. If not, just drop a comment and I'll see what I can do to improve it.
Class definitions:
val or var can be omitted from class parameters which will make the parameter private.
Adding var or val will cause it to be public (that is, method accessors and mutators are generated).
{} can be omitted if the class has no body, that is,
class EmptyClass
Class instantiation:
Generic parameters can be omitted if they can be inferred by the compiler. However note, if your types don't match, then the type parameter is always infered so that it matches. So without specifying the type, you may not get what you expect - that is, given
class D[T](val x:T, val y:T);
This will give you a type error (Int found, expected String)
var zz = new D[String]("Hi1", 1) // type error
Whereas this works fine:
var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}
Because the type parameter, T, is inferred as the least common supertype of the two - Any.
Function definitions:
= can be dropped if the function returns Unit (nothing).
{} for the function body can be dropped if the function is a single statement, but only if the statement returns a value (you need the = sign), that is,
def returnAString = "Hi!"
but this doesn't work:
def returnAString "Hi!" // Compile error - '=' expected but string literal found."
The return type of the function can be omitted if it can be inferred (a recursive method must have its return type specified).
() can be dropped if the function doesn't take any arguments, that is,
def endOfString {
return "myDog".substring(2,1)
}
which by convention is reserved for methods which have no side effects - more on that later.
() isn't actually dropped per se when defining a pass by name paramenter, but it is actually a quite semantically different notation, that is,
def myOp(passByNameString: => String)
Says myOp takes a pass-by-name parameter, which results in a String (that is, it can be a code block which returns a string) as opposed to function parameters,
def myOp(functionParam: () => String)
which says myOp takes a function which has zero parameters and returns a String.
(Mind you, pass-by-name parameters get compiled into functions; it just makes the syntax nicer.)
() can be dropped in the function parameter definition if the function only takes one argument, for example:
def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }
But if it takes more than one argument, you must include the ():
def myOp2(passByNameString:(Int, String) => String) { .. }
Statements:
. can be dropped to use operator notation, which can only be used for infix operators (operators of methods that take arguments). See Daniel's answer for more information.
. can also be dropped for postfix functions
list tail
() can be dropped for postfix operators
list.tail
() cannot be used with methods defined as:
def aMethod = "hi!" // Missing () on method definition
aMethod // Works
aMethod() // Compile error when calling method
Because this notation is reserved by convention for methods that have no side effects, like List#tail (that is, the invocation of a function with no side effects means that the function has no observable effect, except for its return value).
() can be dropped for operator notation when passing in a single argument
() may be required to use postfix operators which aren't at the end of a statement
() may be required to designate nested statements, ends of anonymous functions or for operators which take more than one parameter
When calling a function which takes a function, you cannot omit the () from the inner function definition, for example:
def myOp3(paramFunc0:() => String) {
println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work
When calling a function that takes a by-name parameter, you cannot specify the argument as a parameter-less anonymous function. For example, given:
def myOp2(passByNameString:Int => String) {
println(passByNameString)
}
You must call it as:
myOp("myop3")
or
myOp({
val source = sourceProvider.source
val p = myObject.findNameFromSource(source)
p
})
but not:
myOp(() => "myop3") // Doesn't work
IMO, overuse of dropping return types can be harmful for code to be re-used. Just look at specification for a good example of reduced readability due to lack of explicit information in the code. The number of levels of indirection to actually figure out what the type of a variable is can be nuts. Hopefully better tools can avert this problem and keep our code concise.
(OK, in the quest to compile a more complete, concise answer (if I've missed anything, or gotten something wrong/inaccurate please comment), I have added to the beginning of the answer. Please note this isn't a language specification, so I'm not trying to make it exactly academically correct - just more like a reference card.)
A collection of quotes giving insight into the various conditions...
Personally, I thought there'd be more in the specification. I'm sure there must be, I'm just not searching for the right words...
There are a couple of sources however, and I've collected them together, but nothing really complete / comprehensive / understandable / that explains the above problems to me...:
"If a method body has more than one
expression, you must surround it with
curly braces {…}. You can omit the
braces if the method body has just one
expression."
From chapter 2, "Type Less, Do More", of Programming Scala:
"The body of the upper method comes
after the equals sign ‘=’. Why an
equals sign? Why not just curly braces
{…}, like in Java? Because semicolons,
function return types, method
arguments lists, and even the curly
braces are sometimes omitted, using an
equals sign prevents several possible
parsing ambiguities. Using an equals
sign also reminds us that even
functions are values in Scala, which
is consistent with Scala’s support of
functional programming, described in
more detail in Chapter 8, Functional
Programming in Scala."
From chapter 1, "Zero to Sixty: Introducing Scala", of Programming Scala:
"A function with no parameters can be
declared without parentheses, in which
case it must be called with no
parentheses. This provides support for
the Uniform Access Principle, such
that the caller does not know if the
symbol is a variable or a function
with no parameters.
The function body is preceded by "="
if it returns a value (i.e. the return
type is something other than Unit),
but the return type and the "=" can be
omitted when the type is Unit (i.e. it
looks like a procedure as opposed to a
function).
Braces around the body are not
required (if the body is a single
expression); more precisely, the body
of a function is just an expression,
and any expression with multiple parts
must be enclosed in braces (an
expression with one part may
optionally be enclosed in braces)."
"Functions with zero or one argument
can be called without the dot and
parentheses. But any expression can
have parentheses around it, so you can
omit the dot and still use
parentheses.
And since you can use braces anywhere
you can use parentheses, you can omit
the dot and put in braces, which can
contain multiple statements.
Functions with no arguments can be
called without the parentheses. For
example, the length() function on
String can be invoked as "abc".length
rather than "abc".length(). If the
function is a Scala function defined
without parentheses, then the function
must be called without parentheses.
By convention, functions with no
arguments that have side effects, such
as println, are called with
parentheses; those without side
effects are called without
parentheses."
From blog post Scala Syntax Primer:
"A procedure definition is a function
definition where the result type and
the equals sign are omitted; its
defining expression must be a block.
E.g., def f (ps) {stats} is
equivalent to def f (ps): Unit =
{stats}.
Example 4.6.3 Here is a declaration
and a de?nition of a procedure named
write:
trait Writer {
def write(str: String)
}
object Terminal extends Writer {
def write(str: String) { System.out.println(str) }
}
The code above is implicitly completed
to the following code:
trait Writer {
def write(str: String): Unit
}
object Terminal extends Writer {
def write(str: String): Unit = { System.out.println(str) }
}"
From the language specification:
"With methods which only take a single
parameter, Scala allows the developer
to replace the . with a space and omit
the parentheses, enabling the operator
syntax shown in our insertion operator
example. This syntax is used in other
places in the Scala API, such as
constructing Range instances:
val firstTen:Range = 0 to 9
Here again, to(Int) is a vanilla
method declared inside a class
(there’s actually some more implicit
type conversions here, but you get the
drift)."
From Scala for Java Refugees Part 6: Getting Over Java:
"Now, when you try "m 0", Scala
discards it being a unary operator, on
the grounds of not being a valid one
(~, !, - and +). It finds that "m" is
a valid object -- it is a function,
not a method, and all functions are
objects.
As "0" is not a valid Scala
identifier, it cannot be neither an
infix nor a postfix operator.
Therefore, Scala complains that it
expected ";" -- which would separate
two (almost) valid expressions: "m"
and "0". If you inserted it, then it
would complain that m requires either
an argument, or, failing that, a "_"
to turn it into a partially applied
function."
"I believe the operator syntax style
works only when you've got an explicit
object on the left-hand side. The
syntax is intended to let you express
"operand operator operand" style
operations in a natural way."
Which characters can I omit in Scala?
But what also confuses me is this quote:
"There needs to be an object to
receive a method call. For instance,
you cannot do “println “Hello World!”"
as the println needs an object
recipient. You can do “Console
println “Hello World!”" which
satisfies the need."
Because as far as I can see, there is an object to receive the call...
I find it easier to follow this rule of thumb: in expressions spaces alternate between methods and parameters. In your example, (service.findAllPresentations.get.first.votes.size) must be equalTo(2) parses as (service.findAllPresentations.get.first.votes.size).must(be)(equalTo(2)). Note that the parentheses around the 2 have a higher associativity than the spaces. Dots also have higher associativity, so (service.findAllPresentations.get.first.votes.size) must be.equalTo(2)would parse as (service.findAllPresentations.get.first.votes.size).must(be.equalTo(2)).
service findAllPresentations get first votes size must be equalTo 2 parses as service.findAllPresentations(get).first(votes).size(must).be(equalTo).2.
Actually, on second reading, maybe this is the key:
With methods which only take a single
parameter, Scala allows the developer
to replace the . with a space and omit
the parentheses
As mentioned on the blog post: http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6 .
So perhaps this is actually a very strict "syntax sugar" which only works where you are effectively calling a method, on an object, which takes one parameter. e.g.
1 + 2
1.+(2)
And nothing else.
This would explain my examples in the question.
But as I said, if someone could point out to be exactly where in the language spec this is specified, would be great appreciated.
Ok, some nice fellow (paulp_ from #scala) has pointed out where in the language spec this information is:
6.12.3:
Precedence and associativity of
operators determine the grouping of
parts of an expression as follows.
If there are several infix operations in an expression, then
operators with higher precedence bind
more closely than operators with lower
precedence.
If there are consecutive infix operations e0 op1 e1 op2 . . .opn en
with operators op1, . . . , opn of the
same precedence, then all these
operators must have the same
associativity. If all operators are
left-associative, the sequence is
interpreted as (. . . (e0 op1 e1) op2
. . .) opn en. Otherwise, if all
operators are rightassociative, the
sequence is interpreted as e0 op1 (e1
op2 (. . .opn en) . . .).
Postfix operators always have lower precedence than infix operators. E.g.
e1 op1 e2 op2 is always equivalent to
(e1 op1 e2) op2.
The right-hand operand of a
left-associative operator may consist
of several arguments enclosed in
parentheses, e.g. e op (e1, . . .
,en). This expression is then
interpreted as e.op(e1, . . . ,en).
A left-associative binary operation e1
op e2 is interpreted as e1.op(e2). If
op is rightassociative, the same
operation is interpreted as { val
x=e1; e2.op(x ) }, where x is a fresh
name.
Hmm - to me it doesn't mesh with what I'm seeing or I just don't understand it ;)
There aren't any. You will likely receive advice around whether or not the function has side-effects. This is bogus. The correction is to not use side-effects to the reasonable extent permitted by Scala. To the extent that it cannot, then all bets are off. All bets. Using parentheses is an element of the set "all" and is superfluous. It does not provide any value once all bets are off.
This advice is essentially an attempt at an effect system that fails (not to be confused with: is less useful than other effect systems).
Try not to side-effect. After that, accept that all bets are off. Hiding behind a de facto syntactic notation for an effect system can and does, only cause harm.

Resources