|
View:
New views
7 Messages
—
Rating Filter:
Alert me
|
|
|
Structural types and genericsI'm wondering if there's a cleaner solution to this problem. I have a class called StringTemplate (conceptually similar to Python's StringTemplate class). It's instantied with - a regex that defines the syntax of a variable reference - a "resolver" object that can take a variable name and return a value For maximum flexibility, I chose to model the resolver with a structural type, like so: class StringTemplate(val varRegex: Regex, val resolver: {def get(s: String): Option[String]}) There's a method in the code that resolves a variable reference; it's pretty simple: private def getVar(name: String): String = { resolver.get(name) match { case None => "" case Some(value) => value.toString } } Everything compiles just fine. If I pass a Map[String,String] as the resolver, however, the getVar() method fails at runtime, because Scala generates code that attempts to find the "get" method via reflection. Of course, due to type erasure, the Map classes don't actually have a method with the signature get(String) so the lookup fails. I solved the problem with a kludge: class StringTemplate(val varRegex: Regex, val resolver: {def get(s: String): Option[String]}) { // Kludge: Have to cast the resolver to an Any/Any type, because // structural types work via reflection, and reflection has to work // with type erasure. If a Map[String,String] is passed as the // resolver, Scala will fail to find a "get(String)" method, because, // due to erasure, the REAL method is "get(Any)". Hence this kludged // cast. (At least it's hidden from the caller.) private type ResolverType = {def get(s: Any): Option[Any]} private val varResolver = resolver.asInstanceOf[ResolverType] Then, I changed my getVar() method to use the type-cast varResolver variable, instead, and all is fine. This solution works fine, and the ugliness is hidden within my class; the callers pass in exactly what they expect, never mind the machinations I have to do under the covers. However, with the type cast, it'll now fail on non-generic resolver classes (i.e., those with a get() method that has an explicit String parameter, rather than one that's inferred from a generic type). I can certainly add another kludge to fix that, one that tries the first "correct" resolver, traps the runtime reflection exception, and tries the typecast resolver in the catch clause. I'm just wondering if there's a less... kludgy solution to this problem that (a) I'm just not finding via Google and (b) am just too dense to figure out on my own. -- -Brian Brian Clapper, http://www.clapper.org/bmc/ "It was hell," recalls former child. -- caption to a B. Kliban cartoon |
|
|
Re: Structural types and genericsWhy not try
class StringTemplate(val varRegex : String, val resolver : (String) => Option[String]) On Mon, Jul 6, 2009 at 11:32 PM, Brian Clapper <bmc@...> wrote:
-- Viktor Klang Scala Loudmouth |
|
|
Re: Structural types and genericsOn 7/6/09 5:42 PM, Viktor Klang wrote:
> Why not try > > class StringTemplate(val varRegex : String, val resolver : (String) => > Option[String]) Sure, I can do that. In fact, using a function reference did occur to me, as an alternative to structural typing. But I prefer passing an object rather than a function, for this particular API. Seems cleaner somehow--though I'll admit that's a thoroughly subjective judgment. -- -Brian Brian Clapper, http://www.clapper.org/bmc/ The IQ of the group is the lowest IQ of a member of the group divided by the number of people in the group. |
|
|
Re: Structural types and genericsOn Monday July 6 2009, Brian Clapper wrote:
> On 7/6/09 5:42 PM, Viktor Klang wrote: > > Why not try > > > > class StringTemplate(val varRegex : String, val resolver : (String) > > => Option[String]) > > Sure, I can do that. In fact, using a function reference did occur to > me, as an alternative to structural typing. But I prefer passing an > object rather than a function, You're aware Scala functions are instances, right? They're all instances of classes that implement one of the FunctionN traits (where N is the function arity; traits with values of N from 0 through 22 are defined). > for this particular API. Seems cleaner somehow--though I'll admit > that's a thoroughly subjective judgment. Ignoring implementation details like FunctionN, how is an object cleaner than a function? Randall Schulz |
|
|
Re: Structural types and genericsA function is an object.
http://www.scala-lang.org/docu/files/api/scala/Function1.html
On Mon, Jul 6, 2009 at 5:57 PM, Brian Clapper <bmc@...> wrote:
-- http://erikengbrecht.blogspot.com/ |
|
|
Re: Structural types and genericsErik Engbrecht wrote:
> A function is an object. > > http://www.scala-lang.org/docu/files/api/scala/Function1.html And better yet, some very familiar objects are also functions! :) ||| | > > |trait| /Map/[/A/, +/B/] > | extends |PartialFunction > <http://www.scala-lang.org/docu/files/api/scala/PartialFunction.html>[A > <http://www.scala-lang.org/docu/files/api/scala/collection/Map.html#A>, > B > <http://www.scala-lang.org/docu/files/api/scala/collection/Map.html#B>]| > with |Collection > <http://www.scala-lang.org/docu/files/api/scala/Collection.html>[(A > <http://www.scala-lang.org/docu/files/api/scala/collection/Map.html#A>, > B > <http://www.scala-lang.org/docu/files/api/scala/collection/Map.html#B>)] > http://www.scala-lang.org/docu/files/api/scala/collection/Map.html -0xe1a |
|
|
Re: Structural types and genericsOn 7/6/09 6:05 PM, Randall R Schulz wrote:
> Ignoring implementation details like FunctionN, how is an object cleaner > than a function? It isn't, really, now that I've given it some thought. Thanks. -- -Brian Brian Clapper, http://www.clapper.org/bmc/ Alas, I am dying beyond my means. -- Oscar Wilde, as he sipped champagne on his deathbed |
| Free embeddable forum powered by Nabble | Forum Help |