Donbeo
Donbeo

Reputation: 17617

scala pattern matching with either

I want a function readFile that takes as input a variable file. File can be both a string or a java.io.File. Suppose to have a function readJavaFile that accept a java.io.File as input.

I want to do something like:

def readFile(file:Either[String, File]) = {
   file match {
     case s:String => readJavaFile(new File(s))
     case s:File => readJavaFile(s)
   }
}

What is the right way to implement this? I saw similar questions on SO but they were referring to more complex situations.

EDIT: I am afraid that Either is not the way to follow. I want to be able to call the function as : readFile(s) where s is a string or readFile(f) where f is a File

EDIT: This is my real code:

def csvread(file: File,
             separator: Char=',',
             quote: Char='"',
             escape: Char='\\',
             skipLines: Int = 0): DenseMatrix[Double] = {
    val input = new FileReader(file)
    var mat = CSVReader.read(input, separator, quote, escape, skipLines)
    mat = mat.takeWhile(line => line.length != 0 && line.head.nonEmpty) // empty lines at the end
    input.close()
    if(mat.length == 0) {
      DenseMatrix.zeros[Double](0,0)
    } else {
      DenseMatrix.tabulate(mat.length,mat.head.length)((i,j)=>mat(i)(j).toDouble)
    }
  }

  def csvread(file: String,
              separator: Char=',',
              quote: Char='"',
              escape: Char='\\',
              skipLines: Int = 0): DenseMatrix[Double] = csvread(new File(file), separator, quote, escape, skipLines)

And I want to call it as:

package breeze.linalg

/**
  * Created by donbeo on 07/02/16.
  */

import org.scalatest._
import org.scalatest.junit._
import org.scalatest.prop._
import org.junit.runner.RunWith
import breeze.linalg.csvread
import java.io.File

@RunWith(classOf[JUnitRunner])
class ReadCsvTest extends FunSuite with Checkers{

  test("Try readcsv") {
    val f = csvread(new File("/Users/donbeo/Documents/datasets/glass.csv"))
    val v = csvread("/Users/donbeo/Documents/datasets/glass.csv")

  }

}

but I receive and error:

Error:(41, 16) in package object linalg, multiple overloaded alternatives of method csvread define default arguments.
package object linalg {
               ^

Upvotes: 1

Views: 1711

Answers (3)

Dan Vulpe
Dan Vulpe

Reputation: 1326

I suppose you want something like this:

  def readFile(file:Either[String, File]) = {
    file match {
      case Left(s) => readJavaFile(new File(s))
      case Right(s) => readJavaFile(s)
    }
  }

Either is a collection of two sets: Left and Right. You can also solve it using fold:

def readFile(file: Either[String, File]): File = 
  readJavaFile(file.fold(new File(_), identity))

Upvotes: 4

The Archetypal Paul
The Archetypal Paul

Reputation: 41769

Sounds like a perfect case for overloading to me.

 def readFile(s:String) = readJavaFile(new File(s))
 def readFile(f:File) = readJavaFile(f)

Unless you already have the string-or-file in an Either, putting them into an Either just to get them out again seems more complex than is needed.

Upvotes: 5

dth
dth

Reputation: 2337

What your pattern does, is, match on the type of "file". But that is actualy Either. What you should do instead is match on the kind of Either-instance you have:

file match {
  case Left(s) => readJavaFile(new File(s))
  case Right(s) => readJavaFile(s)
}

What you have would work if your parameter type was Any, but you do not want to do that. (Or the union of File and String, which is something different than Either and something Scala does not have (yet))

Upvotes: 1

Related Questions