I want to do this:
var (a, b) = (0, 0)
a = (b = 100)
but Scala is complaining that
error: type mismatch;
found : Unit
required: Int
What I want is to assign a and b to the same value.
Why Scala make it Unit where it should be Int?
Your statement is an assignment, which returns Unit.
See this related question for reasons why. You can do this, if you want:
scala> var (a,b) = (0,0)
a: Int = 0
b: Int = 0
scala> a = {b = 100; b}
a: Int = 100
scala> var a,b,c,d,e,f,g = 0
a: Int = 0
b: Int = 0
c: Int = 0
d: Int = 0
e: Int = 0
f: Int = 0
g: Int = 0
scala> var f,i,j,k,m,n,o = new Object{}
f: java.lang.Object = $anon$1#11ce012
i: java.lang.Object = $anon$2#baf4ae
j: java.lang.Object = $anon$3#15e68d
k: java.lang.Object = $anon$4#1d3633c
m: java.lang.Object = $anon$5#118317f
n: java.lang.Object = $anon$6#15998cb
o: java.lang.Object = $anon$7#13e6f83
scala>
Why ask why? Assignment expressions have type Unit and that's how it is. No chained assignments. Period.
You can define a special assignment operator (it must end with a colon as it must be right associative) for your own types, or write a generic wrapper (including implit conversions) for general types. I wouldn't recommend to actually use this, but here it goes:
case class M[T](var t:T) {
def =: (m: M[T]):M[T] = {m.t = t ; this}
}
implicit def anyToM[T](v:T) = M(v)
implicit def mToAny[T](m:M[T]) = m.t
def main(args: Array[String]) {
var a = M(0)
var b = M(0)
var c = M(0)
a =: b =: c =: 100
println(a + b + c) //--> 300
}
I think it is always a bad idea to summon heavy magick in order to save a few keystrokes. In Germany we would call this "to shoot sparrows with a cannon"...
case class assign[T](v: T) {
def to(vals: (T => Unit)*) { vals.foreach{ vv => vv(v) } }
}
var (a,b) = (0,0)
assign(39) to (a = _, b = _)
assert(a == 39)
assert(b == 39)
Or you can rename it to emulate a rather simple version of a with statement.
with(20) do (a = _, b = _, print)
Related
I know that one can define an operator in Scala like this :
class value(var valu:Int) {
def +(i:Int) = { this.valu + i }
def ==>(i:Int ) = { this.valu = i }
}
But I cannot seem to overload the = operator like this :
class value(var valu:Int) {
def =(i:Int) = { this.valu = i }
}
Do you know if there is any way to do this?
The syntax for making mutable objects isn't obvious and isn't encountered often because mutability is generally undesirable.
class Value(private var valu:Int) {
def update(i:Int) :Unit = valu = i
}
val v = new Value(19)
v() = 52
= is a reserved word like yield, so to use it as an identifier, you put it in backticks, though I suspect no one does that:
scala> class C(var i: Int) { def `=`(n: Int) = i = n }
defined class C
scala> val c = new C(42)
c: C = C#9efcd90
scala> c.`=`(27)
scala> c.i
res1: Int = 27
scala> c `=` 5
scala> c.i
res3: Int = 5
Compare:
scala> val yield = 2
^
error: illegal start of simple pattern
scala> val `yield` = 2
yield: Int = 2
I am trying to implement a method that should take an arbitrary method or code block and it should convert the method or code-block to retry-able method.
Following example is intended to demonstrate what I need
import scala.util.{Try,Success,Failure}
object Retry {
retry[A, B](f: A => Try[B], r: Int): A => Try[B] = {
// return a function g and when g is invoked with parameters
// f should be tried (if failed) r number of time otherwise
// result of first successful execution of f should be returned
// from g. retry should work with any arbitrary function with
// any number/type of parameters
}
}
If you want to abstract over arity, which is pretty advanced, you'll have to use shapeless, a library for generic programming.
Building on #chengpohi's answer:
import shapeless._, ops.function._
import scala.util.Try
def retry[F, L <: HList, R](f: F, r: Int = 1)(implicit fnToP: FnToProduct.Aux[F, L => R], fnFromP: FnFromProduct.Aux[L => R, F]): F = {
val fn = fnToP(f)
def repeat(a: L): R = {
for (_ <- 0 to r) {
val tried = Try(fn(a))
if (tried.isSuccess) {
return tried.get
}
}
throw new RuntimeException(s"retry $r failed")
}
fnFromP(repeat _)
}
It works:
scala> var i = 0
i: Int = 0
scala> val f = retry( (a: Int) => if (i < 10) {i += 1; println(s"try $i"); throw new RuntimeException} else a * 3, 42)
f: Int => Int = shapeless.ops.FnFromProductInstances$$anon$2$$Lambda$1489/1404497488#1d49a23c
scala> f(5)
try 1
try 2
try 3
try 4
try 5
try 6
try 7
try 8
try 9
try 10
res4: Int = 15
scala> var i = 0
i: Int = 0
scala> val f = retry( (a: String, b: Int) => if (i < 10) {i += 1; println(s"try $i"); throw new RuntimeException} else a * b, 42)
f: (String, Int) => String = shapeless.ops.FnFromProductInstances$$anon$3$$Lambda$1492/121867201#1a22b89c
scala> f("foo", 5)
try 1
try 2
try 3
try 4
try 5
try 6
try 7
try 8
try 9
try 10
res5: String = foofoofoofoofoo
def retry[A, B](f: A => B, r: Int = 1): A => B = {
def repeat(a: A): B = {
for (_ <- 0 to r) {
val tried = Try(f(a))
if (tried.isSuccess) {
return tried.get
}
}
throw new RuntimeException(s"retry $r failed")
}
repeat
}
There is a simple way to do this, try if Success and return, otherwise throw Exception
The on-line documentation doesn't say too much about it (http://www.scala-lang.org/api/2.12.0/scala/collection/mutable/HashTable.html), and it's impossible to find any example of its usage.
I'm wondering how to even put elements into a mutable.HashTable.
Are there any data structure with the same constant time complexity in research and delete operations that i could use?
mutable.HashTable is a trait.
trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashUtils[A]
with default load factor as 75%
private[collection] final def defaultLoadFactor: Int = 750
uses array for implementation,
protected var table: Array[HashEntry[A, Entry]] = new Array(initialCapacity)
1) you have to use implementations of HashTable, which are mutable.HashMap or mutable.LinkedHashMap.
example,
scala> import scala.collection.mutable.HashMap
import scala.collection.mutable.HashMap
scala> new HashMap[String, String]
res9: scala.collection.mutable.HashMap[String,String] = Map()
add element
scala> res9+= "order-id-1" -> "delivered"
res10: res9.type = Map(order-id-1 -> delivered)
scala> res9
res11: scala.collection.mutable.HashMap[String,String] = Map(order-id-1 -> delivered)
access element
scala> res9("order-id-1")
res12: String = delivered
Write complexity should be O(1) same as in hashmap datastructure. You find the hashcode and add to the array of Entry.
def += (kv: (A, B)): this.type = {
val e = findOrAddEntry(kv._1, kv._2)
if (e ne null) e.value = kv._2
this
}
protected def findOrAddEntry[B](key: A, value: B): Entry = {
val h = index(elemHashCode(key))
val e = findEntry0(key, h)
if (e ne null) e else { addEntry0(createNewEntry(key, value), h); null }
}
private[this] def findEntry0(key: A, h: Int): Entry = {
var e = table(h).asInstanceOf[Entry]
while (e != null && !elemEquals(e.key, key)) e = e.next
e
}
private[this] def addEntry0(e: Entry, h: Int) {
e.next = table(h).asInstanceOf[Entry]
table(h) = e
tableSize = tableSize + 1
nnSizeMapAdd(h)
if (tableSize > threshold)
resize(2 * table.length)
}
2. If you use LinkedHashMap it maintains the order of insertion with use of linked entries
#transient protected var firstEntry: Entry = null
#transient protected var lastEntry: Entry = null
example,
scala> import scala.collection.mutable.LinkedHashMap
import scala.collection.mutable.LinkedHashMap
scala> LinkedHashMap[String, String]()
res0: scala.collection.mutable.LinkedHashMap[String,String] = Map()
scala> res0 += "line-item1" -> "Delivered" += "line-item2" -> "Processing"
res2: res0.type = Map(line-item1 -> Delivered, line-item2 -> Processing)
scala> res0
res3: scala.collection.mutable.LinkedHashMap[String,String] = Map(line-item1 -> Delivered, line-item2 -> Processing)
Can I use multiple parameters in setters?
For example:
private var _a = 0
def a = _a
def a_= (b: Int, c: Int) = _a = b + c
If yes, how can I call the setter method?
What about a tuple?
class A {
private var _a = 0
def a = _a
def a_= (t: (Int, Int)) {
_a = t._1 + t._2
}
}
If you don't like awkward tuple access syntax:
class A {
private var _a = 0
def a = _a
def a_= (t: (Int, Int)) {
t match {
case(b, c) => _a = b + c
}
}
}
Usage:
val x = new A()
x.a = (3, 7)
x.a //10
If you need to set single value from two other values it is probably not a 'setter'. Consider giving this operation a meaningful name or moving it out of this class.
private var _s: Whatever = // init
def s_=(newValue: Whatever): Unit = _setter = newValue
...
implicit def t2whatever(t: (SomeTypeA, SomeTypeB)): Whatever = // some logic here
now we cal call our setter
obj.setter = sta -> stb
// or
obj.setter = (sta, stb)
Which is more or less the same as with plain tuples however, setter semantic isn't mangled.
In case its internal operations in may look like:
class Z {
private var _s = // init
def s = _s
def s_=(newValue: S) = _s = newValue
}
object Z {
def toS(a: S, b: S): S = ChineseZodiac.choose(0.14 * a, math.PI + b)
}
and then
obj.s = Z.toS(1, 2)
What is wrong is the following method?
def someMethod(funcs: => Option[String]*) = {
...
}
That actually "works" under 2.7.7 if you add parens:
scala> def someMethod(funcs: => (Option[String]*)) = funcs
someMethod: (=> Option[String]*)Option[String]*
except it doesn't actually work at runtime:
scala> someMethod(Some("Fish"),None)
scala.MatchError: Some(Fish)
at scala.runtime.ScalaRunTime$.boxArray(ScalaRunTime.scala:136)
at .someMethod(<console>:4)
at .<init>(<console>:6)
at .<clinit>(<console>) ...
In 2.8 it refuses to let you specify X* as the output of any function or by-name parameter, even though you can specify it as an input (this is r21230, post-Beta 1):
scala> var f: (Option[Int]*) => Int = _
f: (Option[Int]*) => Int = null
scala> var f: (Option[Int]*) => (Option[Int]*) = _
<console>:1: error: no * parameter type allowed here
var f: (Option[Int]*) => (Option[Int]*) = _
But if you try to convert from a method, it works:
scala> def m(oi: Option[Int]*) = oi
m: (oi: Option[Int]*)Option[Int]*
scala> var f = (m _)
f: (Option[Int]*) => Option[Int]* = <function1>
scala> f(Some(1),None)
res0: Option[Int]* = WrappedArray(Some(1), None)
So it's not entirely consistent.
In any case, you can possibly achieve what you want by passing in an Array and then sending that array to something that takes repeated arguments:
scala> def aMethod(os: Option[String]*) { os.foreach(println) }
aMethod: (os: Option[String]*)Unit
scala> def someMethod(funcs: => Array[Option[String]]) { aMethod(funcs:_*) }
someMethod: (funcs: => Array[Option[String]])Unit
scala> someMethod(Array(Some("Hello"),Some("there"),None))
Some(Hello)
Some(there)
None
If you really want to (easily) pass a bunch of lazily evaluated arguments, then you need a little bit of infrastructure that as far as I know doesn't nicely exist in the library (this is code for 2.8; view it as inspiration for a similar strategy in 2.7):
class Lazy[+T](t: () => T, lt: Lazy[T]) {
val params: List[() => T] = (if (lt eq null) Nil else t :: lt.params)
def ~[S >: T](s: => S) = new Lazy[S](s _,this)
}
object Lz extends Lazy[Nothing](null,null) {
implicit def lazy2params[T : Manifest](lz: Lazy[T]) = lz.params.reverse.toArray
}
Now you can easily create a bunch of parameters that are lazily evaluated:
scala> import Lz._ // To get implicit def
import Lz._
scala> def lazyAdder(ff: Array[()=>Int]) = {
| println("I'm adding now!");
| (0 /: ff){(n,f) => n+f()}
| }
lazyAdder: (ff: Array[() => Int])Int
scala> def yelp = { println("You evaluated me!"); 5 }
yelp: Int
scala> val a = 3
a: Int = 3
scala> var b = 7
b: Int = 7
scala> lazyAdder( Lz ~ yelp ~ (a+b) )
I'm adding now!
You evaluated me!
res0: Int = 15
scala> val plist = Lz ~ yelp ~ (a+b)
plist: Lazy[Int] = Lazy#1ee1775
scala> b = 1
b: Int = 1
scala> lazyAdder(plist)
I'm adding now!
You evaluated me!
res1: Int = 9
Evidently repeated arguments are not available for by-name parameters.