How to access object in a list - Scala - scala

My code is as follows:
class HuffmanNode(val chars: String, val occurrences: Int) {
override def toString: String = "{" + chars + "|" + occurrences + "}"
def absoluteValue: Int = occurrences
def getChars: String = chars
def getOccurrences: String = occurrences.toString
}
object HuffmanNode {
def apply(chars: String, occurrences: Int): HuffmanNode = {
new HuffmanNode(chars, occurrences)
}
}
I'm trying to create a list of HuffmanNode, e.g.:
val PQ: List[HuffmanNode] = List(HuffmanNode("a", 3), HuffmanNode("b", 3))
How do I access the methods inside the HuffmanNode?
I tried doing this:
PQ(0).getChars
But I get an error saying, unable to resolve symbol getChars.
What could the problem be?

Your code does not compile. If I would hazard a guess I would imagine that you are using a list of the singleton instead of an instance of the class (the singleton does not have a getChars method, only the apply).

If you change code as I suggested in edit, there is no problem to invoke getChars method:
class HuffmanNode(val chars: String, val occurrences: Int) {
override def toString: String = "{" + chars + "|" + occurrences + "}"
def absoluteValue: Int = occurrences
def getChars: String = chars
def getOccurrences: String = occurrences.toString
}
object HuffmanNode {
def apply(chars: String, occurrences: Int): HuffmanNode = {
new HuffmanNode(chars, occurrences)
}
}
val PQ: List[HuffmanNode] = List(HuffmanNode("a", 3), HuffmanNode("b", 3))
PQ(1).getChars
I got:
PQ: List[HuffmanNode] = List({a|3}, {b|3})
res0: String = b
However I needed (just to test) remove keyword override from absoluteValue method.

As pointed out by #Assaf Mendelson you refer to the singleton object instead of instance of the class.
In order to fix you code you should create instance of the class instead like:
val PQ = List(HuffmanNode("blabla", 2))
val chars = PQ(0).getChars // now compiles

Related

replace "London\\/India\\/chaina\\/" to "London_India_chaina_"

I have a string val str = "London\\/India\\/chaina\\/" wanted to replace to "London_India_chaina_"
If I am doing
str.replaceAll("\\\/","_")
getting "London\_India\_chaina\_"
Scala String is in essence java String object.
scala> val str = "London/India/chaina/"
str: String = London/India/chaina/
scala> str.replace("/", "_")
res0: String = London_India_chaina_
You are missing one \ character in the first parameter of replaceAll :
object Replace {
def main(args : Array[String]) = {
var str = "London\\/India\\/chaina\\/"
println(str)
println(str.replaceAll("\\\\/","_"))
}
}
Output :
London\/India\/chaina\/
London_India_chaina_
Operating on the string as a sequence of characters,
str map {
case '/' => '_'
case c => c
}
The second case matches any other character different from '/'.
Try this:
val str = "London\\/India\\/chaina\\/"
str.replaceAll("""\\\\/""","_")

How to distinguish triple quotes from single quotes in macros?

I am writing a macro m(expr: String), where expr is an expression in some language (not Scala):
m("SOME EXPRESSION")
m("""
SOME EXPRESSION
""")
When I am parsing the expression I would like to report error messages with proper locations in the source file. To achieve this I should know the location of the string literal itself and the number of quotes of the literal (3 or 1). Unfortunately, I did not find any method that returns the number of quotes of the literal:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object Temp {
def m(s: String) : String = macro mImpl
def mImpl(context: Context)(s: context.Expr[String]): context.universe.Tree = {
import context.universe._
s match {
case l # Literal(Constant(p: String)) =>
if (l.<TRIPLE QUOTES>) {
...
} else {
...
}
case _ =>
context.abort(context.enclosingPosition, "The argument of m must be a string literal")
}
}
}
What should I put instead of <TRIPLE QUOTES>?
The only way i can think of is to access the source file and check for triple quotes:
l.tree.pos.source.content.startsWith("\"\"\"",l.tree.pos.start)
You need also to edit your matching case:
case l # Expr(Literal(Constant(p: String))) =>
Here the version with some explanation:
val tree: context.universe.Tree = l.tree
val pos: scala.reflect.api.Position = tree.pos
val source: scala.reflect.internal.util.SourceFile = pos.source
val content: Array[Char] = source.content
val start: Int = pos.start
val isTriple: Boolean = content.startsWith("\"\"\"",start)

Overriding toString method in Scala Enumeration

How can I override "toString" to make this Scala code acts like the following Java code.
Code in Scala
object BIT extends Enumeration {
type BIT = Value
val ZERO, ONE, ANY = Value
override def toString() =
this match {
case ANY => "x "
case ZERO=> "0 "
case ONE => "1 "
}
}
val b = ONE
println(ONE) // returns ONE
Wanted toString behaviour should produce same output as the following Java code.
public enum BIT {
ZERO, ONE, ANY;
/** print BIT as 0,1, and X */
public String toString() {
switch (this) {
case ZERO:
return "0 ";
case ONE:
return "1 ";
default://ANY
return "X ";
}
}
}
BIT b = ONE;
System.out.println(b); // returns 1
I think I am overriding the wrong "toString" method.
First, yes you are overriding the wrong toString method. You're overriding the method on the BIT object itself, which is not very useful.
Second, you do this much easier by simply doing
object BIT extends Enumeration {
type BIT = Value
val ZERO = Value("0")
val ONE = Value("1")
val ANY = Value("x")
}
Then you can do
println(BIT.ONE) //prints "1"
If you want to set the value and the string you can do it like this:
scala> object BIT extends Enumeration {
| type BIT = Value
| val ZERO = Value(0, "0")
| val ONE = Value(1, "1")
| val ANY = Value("x")
| }
defined module BIT
scala> BIT.ZERO.toString
res2: String = 0
scala> BIT.ZERO.id
res3: Int = 0
scala> BIT.ANY.id
res4: Int = 2
scala> BIT.ANY.toString
res5: String = x

method with angle brackets (<>)

Is it possible to have angle brackets in method names , e.g. :
class Foo(ind1:Int,ind2:Int){...}
var v = new Foo(1,2)
v(1) = 3 //updates ind1
v<1> = 4 //updates ind2
The real situation is obviously more complicated than this!!I am trying to provide a convenient user interface.
This response is not meant to be taken too seriously - just a proof that this can almost be achieved using some hacks.
class Vector(values: Int*) {
val data = values.toArray
def < (i:Int) = new {
def `>_=`(x: Int) {
data(i) = x
}
def > {
println("value at "+ i +" is "+ data(i))
}
}
override def toString = data.mkString("<", ", ", ">")
}
val v = new Vector(1, 2, 3)
println(v) // prints <1, 2, 3>
v<1> = 10
println(v) // prints <1, 10, 3>
v<1> // prints: value at 1 is 10
Using this class we can have a vector that uses <> instead of () for "read" and write access.
The compiler (2.9.0.1) crashes if > returns a value. It might be a bug or a result of misusing >.
Edit: I was wrong; kassens's answer shows how to do it as you want.
It is not possible to implement a method that would be called when you write v<1> = 4 (except, maybe, if you write a compiler plugin?). However, something like this would be possible:
class Foo {
def at(i: Int) = new Assigner(i)
class Assigner(i: Int) {
def :=(v: Int) = println("assigning " + v + " at index " + i)
}
}
Then:
val f = new Foo
f at 4 := 6
With a little trickery you can actually get quite close to what you want.
object Foo {
val a:Array[Int] = new Array(100)
def <(i:Int) = new Updater(a, i)
}
class Updater(a:Array[Int], i:Int) {
def update(x:Int) {
a(i) = x
}
def >() = this
}
Foo<1>() = 123
I am not sure why Scala requires the () though. And yes, this is a bit of a hack...

Problem with Scala's getter/setters

I'm currently learning Scala, and just discovered the way to create custom field getters/setters. I have a simple example working:
class Thing(private val a:Int){
override def toString = "Thing[" + a + "]"
private var _value = a
def value = _value
def value_= (newVal:Int) = _value = newVal
}
On the console I can do:
scala> var t = new Thing(2)
t: dylan.code.Thing = Thing[2]
scala> t.value
res1: Int = 2
scala> t.value = 3
scala> t.value
res2: Int = 3
Now I'm trying to bring this concept to a slightly more complicated example; I'll try to whittle the code down to what's relevant:
abstract class CellExpression[Type] extends Publisher[CellUpdateEvent[Type]] with Subscriber[CellUpdateEvent[Type], CellExpression[Type]]{
protected var cachedValue: Type = recalculateValue()
protected def recalculateValue(): Type
protected def changeValue(newValue: Type):Unit = {
val oldValue = value()
if(newValue != oldValue){
cachedValue = newValue
publish(new CellUpdateEvent(this, oldValue, newValue))
}
}
def value() = cachedValue
def notify(pub: CellExpression[Type], event: CellUpdateEvent[Type]) = changeValue(recalculateValue())
}
//....
class CellVariable[Type](private val initialValue:Type) extends CellExpression[Type]{
cachedValue = initialValue
protected def recalculateValue() = { cachedValue }
override def toString = "CellVariable[" + value + "]"
def value_= (newValue:Type) = {changeValue(newValue)}
}
As far as I can tell, I've done what I need to in order to be able to treate value as a field via its getter and setter. But when I try it out in the console, I get:
scala> var i = new CellVariable(2)
i: dylan.code.CellVariable[Int] = CellVariable[2]
scala> i.value = 3
<console>:11: error: reassignment to val
i.value = 3
^
What have I done wrong, and how can I fix it?
I actually stumbled onto the solution.
The line where I declare my value function: def value() = cachedValue is the culprit.
If I remove the parentheses to make the line def value = cachedValue everything seems to work as I expected.
You cannot change values in Scala. A value is assigned once and only once. If you want to do this then you need to use variables instead of values. In other words, change the declaration from val to var.
The problem is inside one of your class definitions and may be on a line without val because I believe that if you neglect to declare a name, then Scala assumes that it is a value and therefore immutable.
Not sure what you want getters and setters for though. Scala enables you to ignore all of that Java overhead.
It is probably the line that says cachedValue = initialValue because it is not declared with var anywhere in that class. The definition in the other class is a different name because it is in a different scope. You would have to say something like class.varname to change a variable defined in another class.