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

Mutable XML and Elem apply/unapply conflict?

7 replies
Kenner Stross
Joined: 2012-01-22,
User offline. Last seen 42 years 45 weeks ago.
There was a discussion on StackOverflow on ways to insert a node into an XML structure, which is immutable by nature (see http://stackoverflow.com/questions/2199040/scala-xml-building-adding-children-to-existing-nodes). One of the techniques proposed by Daniel Sobral looked basically like this:

class AddChildrenTo(label: String, newChild: Node) extends RewriteRule {  def addChild(n: Node, newChild: Node) = n match {    case Elem(prefix, label, attribs, scope, child @ _*) =>      Elem(prefix, label, attribs, scope, child ++ newChild : _*)    case _ => error("Can only add children to elements!")  }  override def transform(n: Node) = n match {    case n @ Elem(_, `label`, _, _, _*) => addChild(n, newChild)    case other => other  }}
But when I try to use this code, my IDE complains that the Elem creation isn't right because the Elem extractor (i.e., the unapply that filled the case statement) has created a sequence of Node, whereas the constructor (the apply method) wants a few Strings and then a Node:
object Elem {  def apply(prefix: String,label: String, attributes: MetaData, scope: NamespaceBinding, child: Node*) =     new Elem(prefix,label,attributes,scope,child:_*)
  def unapplySeq(n: Node) = n match {    case _: SpecialNode | _: Group  => None    case _                          => Some((n.prefix, n.label, n.attributes, n.scope, n.child))  }}
I'm confused as to how this could ever work.  Aren't the apply() and unapply() methods out-of-sync, in that you could never unapply() and turn around and feed those results into apply()?
I'm sure I'm misunderstanding something, but I'm not sure what it is. If someone could straighten me out and help me understand why the above code doesn't work and how it might be made to work, I'd GREATLY appreciate it.
Thanks,Kenner
dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Mutable XML and Elem apply/unapply conflict?

What IDE? I just verified that the code is well typed as written.

On Sun, Jan 22, 2012 at 17:40, Kenner Stross wrote:
> There was a discussion on StackOverflow on ways to insert a node into an XML
> structure, which is immutable by nature
> (see http://stackoverflow.com/questions/2199040/scala-xml-building-adding-children-to-existing-nodes).
> One of the techniques proposed by Daniel Sobral looked basically like this:
>
>
> class AddChildrenTo(label: String, newChild: Node) extends RewriteRule {
>   def addChild(n: Node, newChild: Node) = n match {
>     case Elem(prefix, label, attribs, scope, child @ _*) =>
>       Elem(prefix, label, attribs, scope, child ++ newChild : _*)
>     case _ => error("Can only add children to elements!")
>   }
>   override def transform(n: Node) = n match {
>     case n @ Elem(_, `label`, _, _, _*) => addChild(n, newChild)
>     case other => other
>   }
> }
>
> But when I try to use this code, my IDE complains that the Elem creation
> isn't right because the Elem extractor (i.e., the unapply that filled the
> case statement) has created a sequence of Node, whereas the constructor (the
> apply method) wants a few Strings and then a Node:
>
> object Elem {
>   def apply(prefix: String,label: String, attributes: MetaData, scope:
> NamespaceBinding, child: Node*) =
>     new Elem(prefix,label,attributes,scope,child:_*)
>
>   def unapplySeq(n: Node) = n match {
>     case _: SpecialNode | _: Group  => None
>     case _                          => Some((n.prefix, n.label,
> n.attributes, n.scope, n.child))
>   }
> }
>
> I'm confused as to how this could ever work.  Aren't the apply() and
> unapply() methods out-of-sync, in that you could never unapply() and turn
> around and feed those results into apply()?
>
> I'm sure I'm misunderstanding something, but I'm not sure what it is. If
> someone could straighten me out and help me understand why the above code
> doesn't work and how it might be made to work, I'd GREATLY appreciate it.
>
> Thanks,
> Kenner
>

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Mutable XML and Elem apply/unapply conflict?

On Sun, Jan 22, 2012 at 17:40, Kenner Stross wrote:
>
> But when I try to use this code, my IDE complains that the Elem creation
> isn't right because the Elem extractor (i.e., the unapply that filled the
> case statement) has created a sequence of Node, whereas the constructor (the
> apply method) wants a few Strings and then a Node:

And then a sequence of nodes, as indicated by the vargarg annotation (Node*).

>
> object Elem {
>   def apply(prefix: String,label: String, attributes: MetaData, scope:
> NamespaceBinding, child: Node*) =
>     new Elem(prefix,label,attributes,scope,child:_*)
>
>   def unapplySeq(n: Node) = n match {
>     case _: SpecialNode | _: Group  => None
>     case _                          => Some((n.prefix, n.label,
> n.attributes, n.scope, n.child))
>   }
> }
>
> I'm confused as to how this could ever work.  Aren't the apply() and
> unapply() methods out-of-sync, in that you could never unapply() and turn
> around and feed those results into apply()?
>
> I'm sure I'm misunderstanding something, but I'm not sure what it is. If
> someone could straighten me out and help me understand why the above code
> doesn't work and how it might be made to work, I'd GREATLY appreciate it.
>
> Thanks,
> Kenner
>

Kenner Stross
Joined: 2012-01-22,
User offline. Last seen 42 years 45 weeks ago.
Re: Mutable XML and Elem apply/unapply conflict?

Sorry, I meant to say a sequence of Nodes after the strings.

I use IntelliJ IDEA 11.0.1, and have found it to be quite accurate in
its marking of problems. In this case, it has underlined "prefix,
label" each with the message: "Type mismatch, expected String, actual
Node." Next, "attribs" is underlined, with the message: "Type
mismatch, expected MetaData, actual Node." Finally, "scope" is also
underlined, and has the message: "Type mismatch, expected
NamespaceBinding, actual Node."

These messages make sense to me given that Elem.apply() is expecting a
String, String, MetaData, NamespaceBinding and Node*, and that
unapplySeq() has returned only a sequence of Nodes. I'm sure I'm
misunderstanding something (as IntelliJ is too, perhaps), as I don't
see how this apply() and unapplySeq() could ever be compatible with
each other.

Thanks for your help.
Kenner

On Jan 22, 12:59 pm, Daniel Sobral wrote:
> On Sun, Jan 22, 2012 at 17:40, Kenner Stross wrote:
>
> > But when I try to use this code, my IDE complains that the Elem creation
> > isn't right because the Elem extractor (i.e., the unapply that filled the
> > case statement) has created a sequence of Node, whereas the constructor (the
> > apply method) wants a few Strings and then a Node:
>
> And then a sequence of nodes, as indicated by the vargarg annotation (Node*).
>
>
>
>
>
>
>
>
>
>
>
> > object Elem {
> >   def apply(prefix: String,label: String, attributes: MetaData, scope:
> > NamespaceBinding, child: Node*) =
> >     new Elem(prefix,label,attributes,scope,child:_*)
>
> >   def unapplySeq(n: Node) = n match {
> >     case _: SpecialNode | _: Group  => None
> >     case _                          => Some((n.prefix, n.label,
> > n.attributes, n.scope, n.child))
> >   }
> > }
>
> > I'm confused as to how this could ever work.  Aren't the apply() and
> > unapply() methods out-of-sync, in that you could never unapply() and turn
> > around and feed those results into apply()?
>
> > I'm sure I'm misunderstanding something, but I'm not sure what it is. If
> > someone could straighten me out and help me understand why the above code
> > doesn't work and how it might be made to work, I'd GREATLY appreciate it.
>
> > Thanks,
> > Kenner
>
> --
> Daniel C. Sobral
>
> I travel to the future all the time.

Kenner Stross
Joined: 2012-01-22,
User offline. Last seen 42 years 45 weeks ago.
Re: Mutable XML and Elem apply/unapply conflict?

But... I finally was able to run a test this morning, and the code
does appear to execute correctly. So... it is apparently just a
misunderstanding on my part (and IntelliJ's, too). So my question
remains: why is this apply() compatible with this unapply()? What
piece of this puzzle am I misunderstanding?

Thanks,
Kenner

On Jan 22, 11:40 am, Kenner Stross wrote:
> There was a discussion on StackOverflow on ways to insert a node into an
> XML structure, which is immutable by nature
> (seehttp://stackoverflow.com/questions/2199040/scala-xml-building-adding-...).
> One of the techniques proposed by Daniel Sobral looked basically like this:
>
> class AddChildrenTo(label: String, newChild: Node) extends RewriteRule {
>   def addChild(n: Node, newChild: Node) = n match {
>     case Elem(prefix, label, attribs, scope, child @ _*) =>
>       Elem(prefix, label, attribs, scope, child ++ newChild : _*)
>     case _ => error("Can only add children to elements!")
>   }
>   override def transform(n: Node) = n match {
>     case n @ Elem(_, `label`, _, _, _*) => addChild(n, newChild)
>     case other => other
>   }
>
> }
>
> But when I try to use this code, my IDE complains that the Elem creation
> isn't right because the Elem extractor (i.e., the unapply that filled the
> case statement) has created a sequence of Node, whereas the constructor
> (the apply method) wants a few Strings and then a Node:
>
> object Elem {
>   def apply(prefix: String,label: String, attributes: MetaData, scope:
> NamespaceBinding, child: Node*) =
>     new Elem(prefix,label,attributes,scope,child:_*)
>
>   def unapplySeq(n: Node) = n match {
>     case _: SpecialNode | _: Group  => None
>     case _                          => Some((n.prefix, n.label,
> n.attributes, n.scope, n.child))
>   }
>
> }
>
> I'm confused as to how this could ever work.  Aren't the apply() and
> unapply() methods out-of-sync, in that you could never unapply() and turn
> around and feed those results into apply()?
>
> I'm sure I'm misunderstanding something, but I'm not sure what it is. If
> someone could straighten me out and help me understand why the above code
> doesn't work and how it might be made to work, I'd GREATLY appreciate it.
>
> Thanks,
> Kenner

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Re: Mutable XML and Elem apply/unapply conflict?

On Mon, Jan 23, 2012 at 13:44, Kenner Stross wrote:
> Sorry, I meant to say a sequence of Nodes after the strings.
>
> I use IntelliJ IDEA 11.0.1, and have found it to be quite accurate in
> its marking of problems. In this case, it has underlined "prefix,
> label" each with the message: "Type mismatch, expected String, actual
> Node." Next, "attribs" is underlined, with the message: "Type
> mismatch, expected MetaData, actual Node." Finally, "scope" is also
> underlined, and has the message: "Type mismatch, expected
> NamespaceBinding, actual Node."
>
> These messages make sense to me given that Elem.apply() is expecting a
> String, String, MetaData, NamespaceBinding and Node*, and that
> unapplySeq() has returned only a sequence of Nodes. I'm sure I'm
> misunderstanding something (as IntelliJ is too, perhaps), as I don't
> see how this apply() and unapplySeq() could ever be compatible with
> each other.

???

I don't understand why do you think unapplySeq is returning a sequence
of nodes. Here's the code you pasted:

object Elem {
def apply(prefix: String,label: String, attributes: MetaData, scope:
NamespaceBinding, child: Node*) =
new Elem(prefix,label,attributes,scope,child:_*)

def unapplySeq(n: Node) = n match {
case _: SpecialNode | _: Group => None
case _ => Some((n.prefix, n.label,
n.attributes, n.scope, n.child))
}
}

Specifically: Some((n.prefix, n.label, n.attributes, n.scope, n.child))

There: String, String, Metadata, NamespaceBinding and Seq[Node].

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Re: Mutable XML and Elem apply/unapply conflict?

On Mon, Jan 23, 2012 at 14:00, Kenner Stross wrote:
> But... I finally was able to run a test this morning, and the code
> does appear to execute correctly. So... it is apparently just a
> misunderstanding on my part (and IntelliJ's, too).  So my question
> remains: why is this apply() compatible with this unapply()?  What
> piece of this puzzle am I misunderstanding?

Ok... question: are you assuming unapplySeq returns a Seq[Node]
because it's unapply*Seq*?

>
> Thanks,
> Kenner
>
>
> On Jan 22, 11:40 am, Kenner Stross wrote:
>> There was a discussion on StackOverflow on ways to insert a node into an
>> XML structure, which is immutable by nature
>> (seehttp://stackoverflow.com/questions/2199040/scala-xml-building-adding-...).
>> One of the techniques proposed by Daniel Sobral looked basically like this:
>>
>> class AddChildrenTo(label: String, newChild: Node) extends RewriteRule {
>>   def addChild(n: Node, newChild: Node) = n match {
>>     case Elem(prefix, label, attribs, scope, child @ _*) =>
>>       Elem(prefix, label, attribs, scope, child ++ newChild : _*)
>>     case _ => error("Can only add children to elements!")
>>   }
>>   override def transform(n: Node) = n match {
>>     case n @ Elem(_, `label`, _, _, _*) => addChild(n, newChild)
>>     case other => other
>>   }
>>
>> }
>>
>> But when I try to use this code, my IDE complains that the Elem creation
>> isn't right because the Elem extractor (i.e., the unapply that filled the
>> case statement) has created a sequence of Node, whereas the constructor
>> (the apply method) wants a few Strings and then a Node:
>>
>> object Elem {
>>   def apply(prefix: String,label: String, attributes: MetaData, scope:
>> NamespaceBinding, child: Node*) =
>>     new Elem(prefix,label,attributes,scope,child:_*)
>>
>>   def unapplySeq(n: Node) = n match {
>>     case _: SpecialNode | _: Group  => None
>>     case _                          => Some((n.prefix, n.label,
>> n.attributes, n.scope, n.child))
>>   }
>>
>> }
>>
>> I'm confused as to how this could ever work.  Aren't the apply() and
>> unapply() methods out-of-sync, in that you could never unapply() and turn
>> around and feed those results into apply()?
>>
>> I'm sure I'm misunderstanding something, but I'm not sure what it is. If
>> someone could straighten me out and help me understand why the above code
>> doesn't work and how it might be made to work, I'd GREATLY appreciate it.
>>
>> Thanks,
>> Kenner

Kenner Stross
Joined: 2012-01-22,
User offline. Last seen 42 years 45 weeks ago.
Re: Mutable XML and Elem apply/unapply conflict?

Oops... how very embarrassing... In my haste, my newness to Scala, and
my assumption that something was wrong per my IDE, I did confuse
unapplySeq()'s input params with its return values. Yes, you are
absolutely right, apply() and unapplySeq() are perfectly in sync. Of
course.

I guess I've stumbled across a small mistake on the part of IntelliJ,
in marking those values as incorrect.

Thanks for setting me straight on this. Sorry to have wasted your time
with my mistake.

Thanks,
Kenner

On Jan 23, 8:57 am, Daniel Sobral wrote:
> On Mon, Jan 23, 2012 at 14:00, Kenner Stross wrote:
> > But... I finally was able to run a test this morning, and the code
> > does appear to execute correctly. So... it is apparently just a
> > misunderstanding on my part (and IntelliJ's, too).  So my question
> > remains: why is this apply() compatible with this unapply()?  What
> > piece of this puzzle am I misunderstanding?
>
> Ok... question: are you assuming unapplySeq returns a Seq[Node]
> because it's unapply*Seq*?
>
>
>
>
>
>
>
>
>
>
>
> > Thanks,
> > Kenner
>
> > On Jan 22, 11:40 am, Kenner Stross wrote:
> >> There was a discussion on StackOverflow on ways to insert a node into an
> >> XML structure, which is immutable by nature
> >> (seehttp://stackoverflow.com/questions/2199040/scala-xml-building-adding-...).
> >> One of the techniques proposed by Daniel Sobral looked basically like this:
>
> >> class AddChildrenTo(label: String, newChild: Node) extends RewriteRule {
> >>   def addChild(n: Node, newChild: Node) = n match {
> >>     case Elem(prefix, label, attribs, scope, child @ _*) =>
> >>       Elem(prefix, label, attribs, scope, child ++ newChild : _*)
> >>     case _ => error("Can only add children to elements!")
> >>   }
> >>   override def transform(n: Node) = n match {
> >>     case n @ Elem(_, `label`, _, _, _*) => addChild(n, newChild)
> >>     case other => other
> >>   }
>
> >> }
>
> >> But when I try to use this code, my IDE complains that the Elem creation
> >> isn't right because the Elem extractor (i.e., the unapply that filled the
> >> case statement) has created a sequence of Node, whereas the constructor
> >> (the apply method) wants a few Strings and then a Node:
>
> >> object Elem {
> >>   def apply(prefix: String,label: String, attributes: MetaData, scope:
> >> NamespaceBinding, child: Node*) =
> >>     new Elem(prefix,label,attributes,scope,child:_*)
>
> >>   def unapplySeq(n: Node) = n match {
> >>     case _: SpecialNode | _: Group  => None
> >>     case _                          => Some((n.prefix, n.label,
> >> n.attributes, n.scope, n.child))
> >>   }
>
> >> }
>
> >> I'm confused as to how this could ever work.  Aren't the apply() and
> >> unapply() methods out-of-sync, in that you could never unapply() and turn
> >> around and feed those results into apply()?
>
> >> I'm sure I'm misunderstanding something, but I'm not sure what it is. If
> >> someone could straighten me out and help me understand why the above code
> >> doesn't work and how it might be made to work, I'd GREATLY appreciate it.
>
> >> Thanks,
> >> Kenner
>
> --
> Daniel C. Sobral
>
> I travel to the future all the time.

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