Scala is not resolving the proper arg type for Java overloaded method with a repeated parameter

Greetings all!

First of all, I’m relatively new to Scala, so I’m sorry if I commit any naming mistake, and you may consider anything here as passible for change, refactoring or even total reconsideration of my own :smile:

I’ve been working on a personal project in Scala 2.12.19, aiming to create unit tests for most of it. In order to retrieve the content of system files, I’ve decided to use the Java API java.nio.file, which I’ve heard is faster and more secure, without needing to close the access, which is a valid advantage for my project. I’ve imported the Files and Path classes, both Java static classes.

To use them in the most testable manner in Scala (therefore, enabling mocks and avoiding spies), I’ve chosen to create a higher-order method that will get the files, passing the functions as arguments for it, with the actual ones I’ll use set as default, as shown below:

import java.nio.charset.{Charset, StandardCharsets}
import java.nio.file.{Files, Path}

class FileCollector {
  val filePath = "/any/file/path"

  def getFileContent(
      path_getter: ((String, String*) => Path) = Path.of,
      file_reader: ((Path) => Array[Byte]) = Files.readAllBytes,
      charset: Charset = StandardCharsets.UTF_8
  ): String = {
    new String(
      file_reader(path_getter(filePath)),
      charset
    )
  }
}

When compiling using SBT 1.9.8 (Java 22), it throws the following error regarding the Path.of default method, set inside the path_getter:

type mismatch;
 found   : (x$1: java.net.URI)java.nio.file.Path <and> (x$1: String, x$2: String*)java.nio.file.Path
 required: (String, String*) => java.nio.file.Path

It seems that the Path.of method is a Java overloaded method, to which Scala does not use the arguments types set to resolve which method option to use.

I’ve already tried to switch to Scala 2.13.13, in which the error first changes to requiring to use Seq instead of repeated parameters due to version updates, and then falls back to the same error when using Seq.

Does anyone know how to handle this problem properly, or have any other suggestions of how to approach the same goals?

In general, I’d recommend using 2.13 on general principles – 2.12 is somewhat long in the tooth, and might cause unnecessary problems simply because it’s a little obsolete. But it’s probably not the root of the problem.

As for the problem itself, I’m honestly not sure of the details, but it smells like the issue has to do with layering repeating parameters. Scala 2 has an odd tricky little :_* syntax for bridging between Seq and repeated parameters, which sometimes comes into play when you are trying to pass through layers of them. (This syntax basically means, “Expand this Seq into a series of parameters instead.”)

Adding a shim with that in the middle seems to get things to at least compile, as in this Scastie. I don’t know if that actually works, but possibly it can get you over the hurdle?

1 Like
path_getter: ((String, Seq[String]) => Path) = (x, xs) => Path.of(x, xs: _*),

and

file_reader(path_getter(filePath, Nil)),

I tried that, but maybe the other answer, which I didn’t try, is equivalent.

The two factors are overload resolution in Scala and no varargs support for function type, only methods.

1 Like

@dutrevis

If you are new to Scala, this might be too much information, so I’ll leave it with you for a quieter moment…

Stepping back from the vararg problem, have you considered swapping out NIO etc for os-lib?

Given that has a Scala specific API, you may find it easier to work with.

I started using that library in preference to NIO last year; I have no intention of going back these days, other than for doing inter operation with third party Java NIO / IO based code, which os-lib does support.

A closing thought - all of IO, NIO and os-lib are well tested in their own right. I’d imagine you’ll have some code that works with the contents of files that you want to test. Are you going to test this code with files as inputs, or with strings or whatever as an isolated component? It would be a lot easier the second way, you can trust the path / file stuff to be reliable and concentrate on your own part.

Even if you do write some component that gathers up files for processing, you may be able to either mock the files / paths, Java-style, or better yet, abstract these into some generic parameter type that can be substituted with a stand in type, Scala-style.

Makes tests easier to write that way - I’d much rather debug my way through test failures using integers and strings than paths and file objects. You can’t always do this - see this gigantic counterexample, but it’s worth a try.

1 Like

Thank you for the comment even if I don’t quite understand it. What is Scastle?

See my comment in the other thread. It’s an online website that allows you to edit, run, and share Scala code. If you look at my “as in this Scastie” above, that’s a live link to a version of the code that compiles.

Thanks…got it!
Next question which seems ridiculous, so I apologize in advance. I am doing exercises from a book and the first statement is
val a = readInt()
This statement gets an error that: “Not found: readInt” I don’t get it.

That can’t be on its own – there’s no such thing. There must be a definition of readInt() to go with it…

It is part of the exercises at the end of a chapter…There are about 30 individual statements each with a scala prompt. The instructions say to try each statement Maybe I have to do an import first, so I tried import scala.io.* and that didn’t help. This so-called elementary scala aint so elementary!

Can you tell us which book / resource, chapter / page number?

According to the API documentation, readInt is included in scala.io.StdIn.

The API docs are your friend!

1 Like

“Introduction to the Art of Programming Using Scala” by Mark Lewis 2013
It’s probably not the best book for me since I already have programming experience. I think I will stay with “Scala for the Impatient” by Cay Horstmann 3rd edition. But I still would like to know how to do the exercises on page 85

@MarkCLewis Any thoughts on this?

Something like this:

$ scala
Welcome to Scala 3.4.1 (21.0.2, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
                                                                                                                        
scala> import scala.io.StdIn.readInt
                                                                                                                        
scala> val a = readInt()
234
val a: Int = 234
                                                                                                                        
scala> val b = readInt()
-321
val b: Int = -321
                                                                                                                        
scala> val minimum = if (a<b) a else b
val minimum: Int = -321
                                                                                                                        
scala>

and then you would continue typing into the REPL.

When you need to type multi-line code in the REPL, to make a line break and continue typing code you can press Shift + Enter instead of Enter.

I think reading a REPL interaction as text might be a bit unintuitive. Mark has hundreds of videos that go with his books.

Thank you all for your fantastic suggestions, @jducoeur, @som-snytt, and @sageserpent-open! Your insights have been incredibly helpful and greatly appreciated! I’ll gather them to conceive the fittest solution for now :smile: @sageserpent-open, thank you specially for the suggestion of swapping out to os-lib . I’ll give a thoughtful reading on your insights ASAP and reply here :bowing_man: