Workarround for Ambiguous Overload

I’m trying to make two methods:

  def count()(using con: Connection): Long = ???

  def count(): Long =
    Using.resource(ds.getConnection())(con => count()(using con))

One creates a new java.sql.Connection, the other requires an implicit Connection as part of a transaction.

But this is code will not compile at the callsite, since scalac gives a ‘Ambiguous overload’ error. Is there a reasonable workarround for this?

I’ve tried two other ideas that didn’t work. First, using a default argument:

def count()(using con: Connection = ds.getConnection()): Long = ???

This doesn’t work because there’s no way to know if the Connection should be close()'d when done.

Then, I tried using scala.util.NotGiven, but that gives the same Ambiguous overload error.

I guess one viable solution is to just keep the first count implementation,

def count()(using con: Connection): Long = ???

And define the transaction methods outside the interface, using context functions:

import javax.sql.DataSource
import java.sql.Connection
import scala.util.Using

def connect[T](ds: DataSource)(fn: Connection ?=> T): T =
  Using.resource(ds.getConnection())(con => fn(using con))

def transact[T](ds: DataSource)(fn: Connection ?=> T): T =
  Using.resource(ds.getConnection())(con =>
    con.setAutoCommit(false)
    try fn(using con)
    catch case t =>
      con.rollback()
      throw t
  )

val myCount: Long = transact(ds) {
  count()
}

Looks like you are using Scala 3.
That a look at this: The @targetName annotation