This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Unapplying StringContext

8 replies
dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.

I tried to implement the unapply trick with StringContext, but I was
unsuccessful. This is the code I used:

class StringMatching(sc: StringContext) {
def unapplySeq(s: String): Option[Seq[String]] = {
val re = (sc.parts map ("\\Q" + _ + "\\E") mkString "(.*)").r
re findFirstMatchIn s map (_.subgroups)
}
}

class Matching(sc: StringContext) {
def matching: StringMatching = new StringMatching(sc)
}

implicit def toMatching(sc: StringContext): Matching = new Matching(sc)

When I try to use it, I get this error:

scala> "23/01/2012" match { case matching"$day/$month/$year" =>
s"$month-$day-$year" }
:13: error: value matching is not a member of StringContext
"23/01/2012" match { case matching"$day/$month/$year" =>
s"$month-$day-$year" }
^
:13: error: not found: value month
"23/01/2012" match { case matching"$day/$month/$year" =>
s"$month-$day-$year" }
^

I just noticed the second error. Why would it complain about month,
but not about either day or year, which come before and after it?

At any rate, matching is clearly found outside pattern matching:

scala> matching"$day/$month/$year"
:13: error: StringMatching does not take parameters
matching"$day/$month/$year"
^

Did I do something wrong, or is there some problem in the implementation?

Eugene Burmako
Joined: 2011-09-17,
User offline. Last seen 42 years 45 weeks ago.
Re: Unapplying StringContext

The problem lies in the pattern matcher. Iirc extractors do not make
use of implicit conversion, plus, even if they did, the patmat
wouldn't allow an extractor of the "new StringContext(blah).id(blah)"
shape. That's something that Adriaan (cc'd) said would be easy to fix.

Also, there's a problem with desugaring. Current implementation of the
interpolator doesn't distinguish between regular and pattern-matching
use cases. Consequently, it doesn't emit Bind("day", Ident("_")) to
allow for pattern matching, but rather generates Ident("day"), which
is clearly incorrect. We plan to address this eventually, but at the
moment personally I am involved in making reflection work, so I can't
promise anything.

On Jan 23, 2:55 pm, Daniel Sobral wrote:
> I tried to implement the unapply trick with StringContext, but I was
> unsuccessful. This is the code I used:
>
> class StringMatching(sc: StringContext) {
>    def unapplySeq(s: String): Option[Seq[String]] = {
>      val re = (sc.parts map ("\\Q" + _ + "\\E") mkString "(.*)").r
>      re findFirstMatchIn s map (_.subgroups)
>    }
>
> }
>
> class Matching(sc: StringContext) {
>   def matching: StringMatching = new StringMatching(sc)
>
> }
>
> implicit def toMatching(sc: StringContext): Matching = new Matching(sc)
>
> When I try to use it, I get this error:
>
> scala> "23/01/2012" match { case matching"$day/$month/$year" =>
> s"$month-$day-$year" }
> :13: error: value matching is not a member of StringContext
>               "23/01/2012" match { case matching"$day/$month/$year" =>
> s"$month-$day-$year" }
>                                         ^
> :13: error: not found: value month
>               "23/01/2012" match { case matching"$day/$month/$year" =>
> s"$month-$day-$year" }
>                                                                           ^
>
> I just noticed the second error. Why would it complain about month,
> but not about either day or year, which come before and after it?
>
> At any rate, matching is clearly found outside pattern matching:
>
> scala> matching"$day/$month/$year"
> :13: error: StringMatching does not take parameters
>               matching"$day/$month/$year"
>               ^
>
> Did I do something wrong, or is there some problem in the implementation?
>
> --
> Daniel C. Sobral
>
> I travel to the future all the time.

adriaanm
Joined: 2010-02-08,
User offline. Last seen 31 weeks 4 days ago.
Re: Re: Unapplying StringContext


On Mon, Jan 23, 2012 at 9:37 AM, Eugene Burmako <eugene [dot] burmako [at] epfl [dot] ch> wrote:
easy to fix.
... in the context of the virtualized pattern matcher
I should have this working at the latest by mid-February (I don't think this is supposed to work in either patmat implementation right now)
cheersadriaan
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: Unapplying StringContext


On Mon, Jan 23, 2012 at 8:01 AM, Adriaan Moors <adriaan [dot] moors [at] epfl [dot] ch> wrote:
I should have this working at the latest by mid-February (I don't think this is supposed to work in either patmat implementation right now)

We're not talking about implicit conversions taking place to satisfy a pattern case, are we? That would be a semantic nightmare.  I hope we're only talking about passing implicit parameters to unapplies.  Even that much scares me as soon as I start thinking about it.  Please confirm what kind of implicitry we're talking about here.  Whatever it is I hope everyone has thought reeeeeeeal hard about it.
dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Re: Unapplying StringContext

On Mon, Jan 23, 2012 at 16:30, Paul Phillips wrote:
>
>
> On Mon, Jan 23, 2012 at 8:01 AM, Adriaan Moors
> wrote:
>>
>> I should have this working at the latest by mid-February (I don't think
>> this is supposed to work in either patmat implementation right now)
>
>
> We're not talking about implicit conversions taking place to satisfy a
> pattern case, are we? That would be a semantic nightmare.  I hope we're only
> talking about passing implicit parameters to unapplies.  Even that much
> scares me as soon as I start thinking about it.  Please confirm what kind of
> implicitry we're talking about here.  Whatever it is I hope everyone has
> thought reeeeeeeal hard about it.

Actually, passing implicit parameter to unapplies works. Adriaan
showed that on Scalathon, iirc, as a work-around to feed data into
case statements.

But I'll be very specific. The implicit being spoken of here is turning this:

case xyzzy"..." => ...

into this:

toXyzzy(ScalaContext("...")).xyzzy.unapplySeq(...)

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: Unapplying StringContext


On Mon, Jan 23, 2012 at 10:43 AM, Daniel Sobral <dcsobral [at] gmail [dot] com> wrote: 
Actually, passing implicit parameter to unapplies works.

I know it does, the key phrase in my email was "to satisfy a pattern case." There is an endless universe of unexpected behavior awaiting anyone who tries to get too clever mixing implicits and patterns.  Because I don't know how many new abilities patterns are sprouting, everything scares me.  Should a pattern var mask an implicit value of the same name, enabling a differently-named from the companion via the implicit scope? But mostly I'm focused on making sure nobody is considering applying implicit conversions to the scrutinee.
But I'll be very specific. The implicit being spoken of here is turning this:

case xyzzy"..." => ...

As long as it's a special form like that I am not overly concerned.
adriaanm
Joined: 2010-02-08,
User offline. Last seen 31 weeks 4 days ago.
Re: Re: Unapplying StringContext
I wasn't planning on adding any implicit resolution to pattern matching, at least not specifically for this purpose. The sip specifies what these string literals expand to, and the same rules as for normal extractors apply: the type of the expanded expression must declare an unapply method. 
The generalisation I had in mind was that, at the very least, we need multi-arglist extractor calls, and ideally we should derive the types of the subpatterns from the format specifier of the format string (and similarly for regexps , XML and Scala quasi quotes). 
I haven't given implicits much thought in this context, but I don't see any obvious issues with allowing implicit resolution while looking for an unapply method on a pattern value. 
Paul, what were you alluding to? (I'll settle for slightly more concrete ominous predictions from the patmat oracle.)
Cheers,adriaan
On 23 Jan 2012, at 13:30, Paul Phillips <paulp [at] improving [dot] org> wrote:



On Mon, Jan 23, 2012 at 8:01 AM, Adriaan Moors <adriaan [dot] moors [at] epfl [dot] ch> wrote:
I should have this working at the latest by mid-February (I don't think this is supposed to work in either patmat implementation right now)

We're not talking about implicit conversions taking place to satisfy a pattern case, are we? That would be a semantic nightmare.  I hope we're only talking about passing implicit parameters to unapplies.  Even that much scares me as soon as I start thinking about it.  Please confirm what kind of implicitry we're talking about here.  Whatever it is I hope everyone has thought reeeeeeeal hard about it.
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: Unapplying StringContext

On Mon, Jan 23, 2012 at 11:22 AM, Adriaan Moors wrote:
> I haven't given implicits much thought in this context, but I don't see any
> obvious issues with allowing implicit resolution while looking for an
> unapply method on a pattern value.
>
> Paul, what were you alluding to? (I'll settle for slightly more concrete
> ominous predictions from the patmat oracle.)

I don't need specifics when I have gut feelings.

Just to make something up, are we talking about something like

x match { case { expr }(p1) => p1 }

where expr is some arbitrary expression and we will demean ourselves
to convert it to something else if it doesn't have an unapply method?

One thing unapplies do is encode part of their matching strategy in
the argument type of the unapply.

def unapply(x: String) = Some(x) filter (_.length > 3)

The author of this unapply wrote it knowing that it would match all
strings of a particular length, and fail on everything else. It acts
in the context of a pattern match a function Any => Option[String],
not String => Option[String].

So I guess what I'm meandering toward is wondering when exactly one
can apply implicit conversions, because unapplies presently use their
types to do more than classify the input and output. There is also
that extractor pattern variables are typed with an expected type
derived from the unapply method's return type, and as we know a change
in the expected type of an expression can materially change behavior.
I start getting real nervous if the actual unapply method called might
turn out to be something other than what it appears to be.

None of this is the actual basis of any of my reservations though:
it's more that I have gazed long into the pattern matcher abyss, and
abyss gazed back into me, and I would like to see a correct
implementation of 2005's pattern matcher specification before I start
having to worry about freaking implicit conversions.

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Re: Unapplying StringContext

On Wed, Jan 25, 2012 at 19:16, Paul Phillips wrote:
>
> I don't need specifics when I have gut feelings.
>
> Just to make something up, are we talking about something like
>
>  x match { case { expr }(p1) => p1 }
>
> where expr is some arbitrary expression and we will demean ourselves
> to convert it to something else if it doesn't have an unapply method?

I just want to make clear that this is not what I expect to happen --
and understand should happen from the SIP -- with string context. And
since this thread is still titled "Unapplying StringContext", I'll
explain just in case.

A string template has the format ident"..." or ident"""...""". This
"ident" is called on "StringContext", so the implicit in case is one
that makes "StringContext(...).ident" valid. Whether that implements
an extractor or not -- let alone of what type signature -- is not
relevant to the implicit resolution.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland