Implicit parameters - how does Scala find the objects?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Implicit parameters - how does Scala find the objects?

David Copeland
Trying to wrap my head around Implicit Paramters and, while I get the concept, I'm a little unclear on how Scala locates suitable objects to provide for implicit parameters.  Consider this code, which is a logger that is abstracting the way in which lists of things are logged.

abstract class ListLogger[T] {
/** Turns the list into a string for logging */
def asString(list:List[T]):String;

}

class Logger {

def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))
def log(message:String) = println(new java.util.Date().toString() + ":" + message)

}

object ImplicitParamsDemo extends Application {
val logger = new Logger

implicit object IntListLogger extends ListLogger[Int] {
def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "," + n
})
}

implicit object StringListLogger extends ListLogger[String] {
def asString(list:List[String]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "\n" + n
})
}

logger.log("This is a message")
logger.logList(List(4,5,6,7))
logger.logList(List("these","are","some","strings"))
}
My desire is to provide the implicit objects as part of the Logger class/package/etc.  The idea being that if I use logList for some set of common types, the Logger class/package could provide implicit objects for use.

However, if I move the two implicit objects into class Logger (or as a peer to class Logger, or as part of class ListLogger), I get compile errors.

How would I accomplish this and/or where does Scala look for matching objects?

Dave
Reply | Threaded
Open this post in threaded view
|

Re: Implicit parameters - how does Scala find the objects?

Jan Lohre
Hi,

you could do it as below. Scala looks for implicit objects/vals/vars in the scope. Although there where discussions on this afaik there is no possibility, that your Logger class "exports" the implicit objects, so the explicit "import logger.Implicits._" on client side is required.

package logger {

  abstract class ListLogger[T] {
    /** Turns the list into a string for logging */
    def asString(list:List[T]):String;

  }

  class Logger {

    def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))

    def log(message:String) = println(new java.util.Date().toString() + ":" + message)

  }
 
  object Implicits {
   
  implicit object IntListLogger extends ListLogger[Int] {

    def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "," + n
    })
  }

  implicit object StringListLogger extends ListLogger[String] {

    def asString(list:List[String]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "\n" + n
    })
  }

  }
}

package example {
  import logger.Logger
  import logger.Implicits._
 
  object ImplicitParamsDemo extends Application {
    val logger = new Logger

    logger.log("This is a message")

    logger.logList(List(4,5,6,7))
    logger.logList(List("these","are","some","strings"))
  }
}

Kind regards,
Jan

2009/7/31 David Copeland <[hidden email]>
Trying to wrap my head around Implicit Paramters and, while I get the concept, I'm a little unclear on how Scala locates suitable objects to provide for implicit parameters.  Consider this code, which is a logger that is abstracting the way in which lists of things are logged.

abstract class ListLogger[T] {
/** Turns the list into a string for logging */
def asString(list:List[T]):String;

}

class Logger {

def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))
def log(message:String) = println(new java.util.Date().toString() + ":" + message)

}

object ImplicitParamsDemo extends Application {
val logger = new Logger

implicit object IntListLogger extends ListLogger[Int] {
def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "," + n
})
}

implicit object StringListLogger extends ListLogger[String] {
def asString(list:List[String]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "\n" + n
})
}

logger.log("This is a message")
logger.logList(List(4,5,6,7))
logger.logList(List("these","are","some","strings"))
}
My desire is to provide the implicit objects as part of the Logger class/package/etc.  The idea being that if I use logList for some set of common types, the Logger class/package could provide implicit objects for use.

However, if I move the two implicit objects into class Logger (or as a peer to class Logger, or as part of class ListLogger), I get compile errors.

How would I accomplish this and/or where does Scala look for matching objects?

Dave

Reply | Threaded
Open this post in threaded view
|

Re: Implicit parameters - how does Scala find the objects?

Kevin Wright-4
Plus there's also package objects available in Scala 2.8, which I suspect will become the new idiomatic location for implicits.

I'm not 100% certain how the feature interacts with scoping though, and whether you still need to manually import them.



On Fri, Jul 31, 2009 at 8:50 PM, Jan Lohre <[hidden email]> wrote:
Hi,

you could do it as below. Scala looks for implicit objects/vals/vars in the scope. Although there where discussions on this afaik there is no possibility, that your Logger class "exports" the implicit objects, so the explicit "import logger.Implicits._" on client side is required.

package logger {


  abstract class ListLogger[T] {
    /** Turns the list into a string for logging */
    def asString(list:List[T]):String;

  }

  class Logger {

    def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))

    def log(message:String) = println(new java.util.Date().toString() + ":" + message)

  }
 
  object Implicits {

   
  implicit object IntListLogger extends ListLogger[Int] {

    def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "," + n
    })
  }

  implicit object StringListLogger extends ListLogger[String] {

    def asString(list:List[String]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "\n" + n
    })
  }

  }
}

package example {
  import logger.Logger
  import logger.Implicits._

 
  object ImplicitParamsDemo extends Application {
    val logger = new Logger

    logger.log("This is a message")

    logger.logList(List(4,5,6,7))
    logger.logList(List("these","are","some","strings"))
  }
}

Kind regards,
Jan

2009/7/31 David Copeland <[hidden email]>

Trying to wrap my head around Implicit Paramters and, while I get the concept, I'm a little unclear on how Scala locates suitable objects to provide for implicit parameters.  Consider this code, which is a logger that is abstracting the way in which lists of things are logged.

abstract class ListLogger[T] {
/** Turns the list into a string for logging */
def asString(list:List[T]):String;

}

class Logger {

def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))
def log(message:String) = println(new java.util.Date().toString() + ":" + message)

}

object ImplicitParamsDemo extends Application {
val logger = new Logger

implicit object IntListLogger extends ListLogger[Int] {
def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "," + n
})
}

implicit object StringListLogger extends ListLogger[String] {
def asString(list:List[String]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "\n" + n
})
}

logger.log("This is a message")
logger.logList(List(4,5,6,7))
logger.logList(List("these","are","some","strings"))
}
My desire is to provide the implicit objects as part of the Logger class/package/etc.  The idea being that if I use logList for some set of common types, the Logger class/package could provide implicit objects for use.

However, if I move the two implicit objects into class Logger (or as a peer to class Logger, or as part of class ListLogger), I get compile errors.

How would I accomplish this and/or where does Scala look for matching objects?

Dave


Reply | Threaded
Open this post in threaded view
|

Re: Implicit parameters - how does Scala find the objects?

David Copeland-3
In reply to this post by Jan Lohre
Awesome, thanks.  That makes a lot of sense actually.  I'm curious as to why you can't use implicit objects at the top level (i.e. why do I need to wrap them into an object?)

Dave

On Fri, Jul 31, 2009 at 3:50 PM, Jan Lohre <[hidden email]> wrote:
Hi,

you could do it as below. Scala looks for implicit objects/vals/vars in the scope. Although there where discussions on this afaik there is no possibility, that your Logger class "exports" the implicit objects, so the explicit "import logger.Implicits._" on client side is required.

package logger {


  abstract class ListLogger[T] {
    /** Turns the list into a string for logging */
    def asString(list:List[T]):String;

  }

  class Logger {

    def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))

    def log(message:String) = println(new java.util.Date().toString() + ":" + message)

  }
 
  object Implicits {

   
  implicit object IntListLogger extends ListLogger[Int] {

    def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "," + n
    })
  }

  implicit object StringListLogger extends ListLogger[String] {

    def asString(list:List[String]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "\n" + n
    })
  }

  }
}

package example {
  import logger.Logger
  import logger.Implicits._

 
  object ImplicitParamsDemo extends Application {
    val logger = new Logger

    logger.log("This is a message")

    logger.logList(List(4,5,6,7))
    logger.logList(List("these","are","some","strings"))
  }
}

Kind regards,
Jan

2009/7/31 David Copeland <[hidden email]>

Trying to wrap my head around Implicit Paramters and, while I get the concept, I'm a little unclear on how Scala locates suitable objects to provide for implicit parameters.  Consider this code, which is a logger that is abstracting the way in which lists of things are logged.

abstract class ListLogger[T] {
/** Turns the list into a string for logging */
def asString(list:List[T]):String;

}

class Logger {

def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))
def log(message:String) = println(new java.util.Date().toString() + ":" + message)

}

object ImplicitParamsDemo extends Application {
val logger = new Logger

implicit object IntListLogger extends ListLogger[Int] {
def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "," + n
})
}

implicit object StringListLogger extends ListLogger[String] {
def asString(list:List[String]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "\n" + n
})
}

logger.log("This is a message")
logger.logList(List(4,5,6,7))
logger.logList(List("these","are","some","strings"))
}
My desire is to provide the implicit objects as part of the Logger class/package/etc.  The idea being that if I use logList for some set of common types, the Logger class/package could provide implicit objects for use.

However, if I move the two implicit objects into class Logger (or as a peer to class Logger, or as part of class ListLogger), I get compile errors.

How would I accomplish this and/or where does Scala look for matching objects?

Dave


Reply | Threaded
Open this post in threaded view
|

Re: Implicit parameters - how does Scala find the objects?

Kevin Wright-4
I'm pretty sure an implicit object can be top-level within a package, but it still needs to be brought into scope via an import.
so
    import some.package._
should bring in all implicit objects from some.package


The real benefit of putting implicit objects inside another object is that you can then deal with them as class dependant types.

if Foo and Bar are both singleton objects with a common trait t, then you can code something like this:

class C(t : SomeType) {
    import t._
}

passing Foo or Bar into the constructor can then totally reconfigure the way that C works.


On Sat, Aug 1, 2009 at 12:16 AM, David Copeland <[hidden email]> wrote:
Awesome, thanks.  That makes a lot of sense actually.  I'm curious as to why you can't use implicit objects at the top level (i.e. why do I need to wrap them into an object?)

Dave

On Fri, Jul 31, 2009 at 3:50 PM, Jan Lohre <[hidden email]> wrote:
Hi,

you could do it as below. Scala looks for implicit objects/vals/vars in the scope. Although there where discussions on this afaik there is no possibility, that your Logger class "exports" the implicit objects, so the explicit "import logger.Implicits._" on client side is required.

package logger {


  abstract class ListLogger[T] {
    /** Turns the list into a string for logging */
    def asString(list:List[T]):String;

  }

  class Logger {

    def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))

    def log(message:String) = println(new java.util.Date().toString() + ":" + message)

  }
 
  object Implicits {

   
  implicit object IntListLogger extends ListLogger[Int] {

    def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "," + n
    })
  }

  implicit object StringListLogger extends ListLogger[String] {

    def asString(list:List[String]) = list.foldLeft("")((s,n) => {
      if (s.length == 0) s + n
      else s + "\n" + n
    })
  }

  }
}

package example {
  import logger.Logger
  import logger.Implicits._

 
  object ImplicitParamsDemo extends Application {
    val logger = new Logger

    logger.log("This is a message")

    logger.logList(List(4,5,6,7))
    logger.logList(List("these","are","some","strings"))
  }
}

Kind regards,
Jan

2009/7/31 David Copeland <[hidden email]>

Trying to wrap my head around Implicit Paramters and, while I get the concept, I'm a little unclear on how Scala locates suitable objects to provide for implicit parameters.  Consider this code, which is a logger that is abstracting the way in which lists of things are logged.

abstract class ListLogger[T] {
/** Turns the list into a string for logging */
def asString(list:List[T]):String;

}

class Logger {

def logList[T](list:List[T])(implicit lister:ListLogger[T]) = log(lister.asString(list))
def log(message:String) = println(new java.util.Date().toString() + ":" + message)

}

object ImplicitParamsDemo extends Application {
val logger = new Logger

implicit object IntListLogger extends ListLogger[Int] {
def asString(list:List[Int]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "," + n
})
}

implicit object StringListLogger extends ListLogger[String] {
def asString(list:List[String]) = list.foldLeft("")((s,n) => {
if (s.length == 0) s + n
else s + "\n" + n
})
}

logger.log("This is a message")
logger.logList(List(4,5,6,7))
logger.logList(List("these","are","some","strings"))
}
My desire is to provide the implicit objects as part of the Logger class/package/etc.  The idea being that if I use logList for some set of common types, the Logger class/package could provide implicit objects for use.

However, if I move the two implicit objects into class Logger (or as a peer to class Logger, or as part of class ListLogger), I get compile errors.

How would I accomplish this and/or where does Scala look for matching objects?

Dave