So you already have a **Typeclass**.

Was that `MatirxOrFunction`

added after our conversation? or it has been there since the beginning?

An **ADT** *(algebraic data type)* is just a fancy name for a sealed hierarchy of types.

Examples:

### Option

An **Option** is `Some`

with a value or a `None`

```
sealed trait Option[+T]
final case class Some[+T](value: T) extends Option[T]
final case object None extends Option[Nothing]
```

### List

A **List** is an empty list or a non-empty list *(called cons)* with a head *(a value)* and a tail *(a list)*.

```
sealed trait List[+T]
final case class Cons[+T](head: T, tail: List[T]) extends List[T]
final case object Nil extends List[Nothing]
```

###
*etc* …

### UserDefined?

Maybe you can model your `UserDefined`

as an ADT instead.

```
sealed trait UserDefined[T] {
def data: T
}
type Matrix = ArraySeq[ArraySeq[Double]
type MatrixFun = Matrix => Matrix
final case class MatrixUserDefined(data: Matrix) extends UserDefined[Matrix]
final case class MatrixFunUserDefined(data: MatrixFun) extends UserDefined[MatrixFun]
```

That way you can differentiate both types either as an overload or with **pattern matching** which would be the more common approach.

```
object Foo {
private def processMatrix(matrix: Matrix): Unit = {
}
private def processMatrixFun(matrixFun: MatrixFun): Unit = {
}
def processUserDefined[T](data: UserDefined[T]): Unit = data match {
case MatrixUserDefined(matrix) => processMatrix(matrix) // We statically know that matrix is of type Matrix.
case MatrixFunUserDefined(matrixFun) => processMatrixFun(matrixFun) // We statically know that matrixFun is of type MatrixFun.
}
}
```

PS: Not sure why you need that `var z`

, but please reconsider its use.

Mutability is in general discouraged, especially inside a **case class**.