Concise way of copying objects in Scala - scala

OCaml exposes a concise syntax for copying records having a lot of fields.
type t = {
x : int;
y : int;
z : int;
}
let _ =
let v = {x = 1; y = 2; z = 3} in
{v with z = 42}
Is there a similar syntax for Scala's case classes?

Case classes define not just equals, hashCode and toString methods, but also copy. Fortunately the copy method is defined in a way that the current values of the this object are the default parameters, but you can change any of them using named arguments. Your example would look like this:
case class Type(
x : int,
y : int,
z : int,
)
val v = Type(x = 1, y = 2, z = 3)
v.copy(z=42)
But you can also use one of the lensing libraries too. (I think both scalaz and shapeless has one.)

Related

How Scala compiler deals with potential multiple assignments of values

val-variables in Scala should have the following properties, ensured during compilation, not later in runtime:
the immutable variable can not be used (a in "read") before being assigned to (bound).
the immutable variable can not be assigned again after being assigned once.
According to tutorials and docs it is not required to assign the val immediately at the declaration point as long as type is specified.
http://www.tutorialspoint.com/scala/scala_variables.htm
http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#value-declarations-and-definitions
But this seems to create a loophole
def fn1(x: Int, y: Int): Int = {
val const2 : Int
const2 = 0
if (x < 10) const2 = x
if (y > 10) const2 = y
const2
}
def fn2(x: Int, y: Int): Int = {
val const2 : Int
var i: Int
for( i <- x to y ){
const2 = 0
}
const2
}
In these both examples it seems impossible to the compiler to predict whether the assignment would be singular or not. So the compiler does not have standing to prohibit this code from being compiled, but it equally does not have grounds to warrant the singular-assignment nature of val-variables in every execution path possible at runtime.
Whatever compiler would do, compile the code or throw an error instead, it might end on the wrong side. So what should it do, specifications-wise ?
PS. a minor question with documentation: the chapter 4.1 has says
PatDef ::= Pattern2 {‘,’ Pattern2}
Why is it "Pattern2" repeated and having the same numeric index?
Should it perhaps be merely Pattern {‘,’ Pattern} instead or perhaps Pattern1 {‘,’ Pattern2} ?
This is illegal:
val const2 : Int
const2 = 0
vals cannot be reassigned after declaration, period.

'let...in' expression in Scala

In OCaml, the let...in expression allows you to created a named local variable in an expression rather than a statement. (Yes I know that everything is technically an expression, but Unit return values are fairly useless.) Here's a quick example in OCaml:
let square_the_sum a b = (* function definition *)
let sum = a + b in (* declare a named local called sum *)
sum * sum (* return the value of this expression *)
Here's what I would want the equivalent Scala to look like:
def squareTheSum(a: Int, b: Int): Int =
let sum: Int = a + b in
sum * sum
Is there anything in Scala that I can use to achieve this?
EDIT:
You learn something new every day, and this has been answered before.
object ForwardPipeContainer {
implicit class ForwardPipe[A](val value: A) extends AnyVal {
def |>[B](f: A => B): B = f(value)
}
}
import ForwardPipeContainer._
def squareTheSum(a: Int, b: Int): Int = { a + b } |> { sum => sum * sum }
But I'd say that is not nearly as easy to read, and is not as flexible (it gets awkward with nested lets).
You can nest val and def in a def. There's no special syntax; you don't need a let.
def squareTheSum(a: Int, b: Int): Int = {
val sum = a + b
sum * sum
}
I don't see the readability being any different here at all. But if you want to only create the variable within the expression, you can still do that with curly braces like this:
val a = 2 //> a : Int = 2
val b = 3 //> b : Int = 3
val squareSum = { val sum = a + b; sum * sum } //> squareSum : Int = 25
There is no significant difference here between a semicolon and the word "in" (or you could move the expression to the next line, and pretend that "in" is implied if it makes it more OCaml-like :D).
val squareSum = {
val sum = a + b // in
sum * sum
}
Another, more technical, take on this: Clojure's 'let' equivalent in Scala. I think the resulting structures are pretty obtuse compared to the multi-statement form.

Scala: is it possible to make a method "+" work like this: x + y = z?

I have a graph, with each vertex connected to 6 neighbors.
While constructing the graph and making declarations of the connections, I would like to use a syntax like this:
1. val vertex1, vertex2 = new Vertex
2. val index = 3 // a number between 0 and 5
3. vertex1 + index = vertex2
The result should be that vertex2 be declared assigned as index-th neighbor of vertex1, equivalent to:
4. vertex1.neighbors(index) = vertex2
While frobbing with the implementation of Vertex.+, I came up with the following:
5. def +(idx: Int) = neighbors(idx)
which, very surprisingly indeed, did not cause line 3 to be underlined red by my IDE (IntelliJIdea, BTW).
However, compilation of line 3 offsprang the following message:
error: missing arguments for method + in class Vertex;
follow this method with `_' if you want to treat it as a partially applied function
Next, I tried with an extractor, but actually, that doesn't seem to fit the case very well.
Does anybody have any clue if what I'm trying to achieve is anywhat feasible?
Thank you
You probably can achieve what you want by using := instead of =. Take a look at this illustrating repl session:
scala> class X { def +(x:X) = x; def :=(x:X) = x }
defined class X
scala> val a = new X;
a: X = X#7d283b68
scala> val b = new X;
b: X = X#44a06d88
scala> val c = new X;
c: X = X#fb88599
scala> a + b := c
res8: X = X#fb88599
As one of the comments stated, the custom = requires two parameter, for example vertex1(i)=vertex2 is dessugared to vertext.update(i,vertex2) thus forbidding the exact syntax you proposed. On the other hand := is a regular custom operator and a:=b will dessugar to a.:=(b).
Now we still have one consideration to do. Is the precedence going to work as you intent? The answer is yes, according to the Language Specification section 6.12.3. + has higher precedence than :=, so it ends up working as (a+b):=c.
Not exactly what you want, just playing with right-associativity:
scala> class Vertex {
| val neighbors = new Array[Vertex](6)
| def :=< (n: Int) = (this, n)
| def >=: (conn: (Vertex, Int)) {
| val (that, n) = conn
| that.neighbors(n) = this
| this.neighbors((n+3)%6) = that
| }
| }
defined class Vertex
scala> val a, b, c, d = new Vertex
a: Vertex = Vertex#c42aea
b: Vertex = Vertex#dd9f68
c: Vertex = Vertex#ca0c9
d: Vertex = Vertex#10fed2c
scala> a :=<0>=: b ; a :=<1>=: c ; d :=<5>=: a
scala> a.neighbors
res25: Array[Vertex] = Array(Vertex#dd9f68, Vertex#ca0c9, Vertex#10fed2c, null, null, null)

How to use IntInf or LargeInt in SML?

I want to to perform computations with large integers in SML, through functions like pow in this link:
http://www.standardml.org/Basis/int-inf.html#IntInf:STR:SPEC
But how do I get to use this "library"?
UPDATE:
Thanks for the answer. I got it. I also had to change the limit for printing with
Control.Print.intinfDepth := 10000;
I made my own pow function for IntInfs (and it works) like this:
fun power 0 = IntInf.toLarge 1
| power n = IntInf.toLarge 2 * power(n-1);
It depends on which implementation you use, but generally you need to convert your Int's to LageInt/InfInf types with the Int.toLarge:
(* will be types as an IntInf *)
val aa = 10983298432984329843298432984329843298432987987987432987987987432987
val a = IntInf.pow(aa,10);
(* explicit type as if some other constraint had enforced this*)
val b = 10 : int
val c = Int.toLarge b;
val d = IntInf.pow(c, b);
The variable aa may not be parsed in your interpreter. It depends on what you use. I have tested it in poly and mlton.
where the above gets the types (given by mlton with -show-basis flag):
val a: intInf
val aa: intInf
val b: int32
val c: intInf
val d: intInf
-fun prod (a: IntInf.int, b:IntInf.int) : IntInf.int = a+b;
val prod = fn : IntInf.int * IntInf.int -> IntInf.int
for example
-> on how to represent a big integer : IntInf.int as a parameter inside a function

Named parameters lead to maintenance problems and inferior readability?

With named parameters like
def f(x : Int = 1, y : Int = 2) = x * y
your parameter names become part of the interface
f(x=3)
Now if you want to change the parameter names locally, you are forced to perserve the public name of the parameter:
def f(x : Int = 1, y : Int = 2) = {
val (a,b) = (x,y)
a * b
}
If this a real problem? Is there a syntax to support this directly? Who do other languages handle this?
A small illustration of the problems you can run into if you switch parameter names, as suggested by Jon.
trait X{ def f(x : Int, y : Int) }
class A extends X{
override def f(y : Int, x : Int) = println("" + y + x)
}
val a = new A
scala> a.f(x = 1, y = 2)
21
scala> (a : X).f(x = 1, y = 2)
12
Yes, the parameter name is effectively part of the public interface. This is a "problem" for any language which has named arguments - or indeed produces code which is consumed by languages supporting named arguments. Sometimes this isn't well understood.
For example, C# 3 doesn't support named arguments - but VB does. So if you create a library in C# 3, someone builds against it in VB, then changing parameter names counts as a breaking change.
Ultimately some of this will be handled by refactoring tools, but it boils down to the same sort of caution as with any other aspect of a public API... you need to be very cautious.
You should also be very cautious when overriding a method with parameters - use the same parameter names as the original method, or you could cause some very subtle issues. (In particular, switching round the names of parameters would be very evil...)
I don't know about the "inferior readability" part of your title. The few times I used named parameters, it was to provide default values like increment:Int = 100000, maxCount:Int = 1000000. I think it helps readability when you have to changed on value where you call the function.