Home > Software engineering >  Why " " works but "::" doesn't work even though they have same logic in sc
Why " " works but "::" doesn't work even though they have same logic in sc

Time:01-16

abstract class MyList[ A] {
    def head: A
    def next: MyList[A]
    def isEmpty: Boolean
    def add[B >: A](element: B): MyList[B]
    def printElements: String
    override def toString: String = s"[$printElements]"
    def   [B >: A](list: MyList[B]): MyList[B]
    def ::[B >: A](list: MyList[B]): MyList[B]
}

case object Empty extends MyList[Nothing] {
    def head: Nothing = throw new NoSuchElementException
    def next: MyList[Nothing] = throw new NoSuchElementException
    def isEmpty: Boolean = true
    def add[B >: Nothing](element: B): MyList[B] = Cons(element, Empty)
    def printElements: String = ""
    def   [B >: Nothing](list: MyList[B]): MyList[B] = list
    def ::[B >: Nothing](list: MyList[B]): MyList[B] = list
}

case class Cons[ A](h: A, t: MyList[A]) extends MyList[A] {
    def this(h: A) = this(h, Empty)
    def head: A = h
    def next: MyList[A] = t
    def isEmpty: Boolean = false
    def add[B >: A](element: B): MyList[B] = Cons(element, this)
    def printElements: String =
        if (t.isEmpty) s"$h"
        else s"$h ${t.printElements}"

    def   [B >: A](list: MyList[B]): MyList[B] = Cons(h, next    list)
    def ::[B >: A](list: MyList[B]): MyList[B] = Cons(h, next :: list)
}

object runTest extends App {
    val a = Empty.add(1).add(2).add(3)
    val b = Empty.add(4).add(5).add(6)
    println(a)
    println(b)
    println(a    b) //[3 2 1 6 5 4] good
    println(a :: b) //[6 3 5 2 4 1] why???
}

I tried to concat two MyList, but the problem is, " " and "::" have the same logic but " " will print [3 2 1 6 5 4], which makes sense, while "::" will prints [6 3 5 2 4 1]

CodePudding user response:

From the 2.13 language specifications (I can't seem to find the scala3 version, but this part hasn't changed):

Operators ending in a colon ‘:’ are right-associative. All other operators are left-associative.

[...]

If op is right-associative and its parameter is passed by name, the same operation is interpreted as e2.op(e1)


So your a :: b is the same as b.::(a), and

def ::[B >: A](list: MyList[B]): MyList[B] = Cons(h, next :: list)

is

def ::[B >: A](list: MyList[B]): MyList[B] = Cons(h, list.::(next))

which explains the [6 3 5 2 4 1] you're getting.

You can get the result you want by using

def ::[B >: A](list: MyList[B]): MyList[B] = Cons(h, next.::(list))
...
println(a.::(b))
  •  Tags:  
  • Related