Search code examples
xmlscalacompanion-object

Scala – companion object & apply: non understandable error


I can't create a class representing an XML parsed document, using a companion object.

Here is the code of the class:

package models

import javax.xml.bind.Element
import scala.xml.Elem
import javax.xml.validation.SchemaFactory
import javax.xml.transform.stream.StreamSource


trait MyXML {

case class ElémentXML(code_xml: scala.xml.Elem) {

def validate: Boolean = {

try ({
  val schemaLang = "http://www.w3.org/2001/XMLSchema"
  val factory = SchemaFactory.newInstance(schemaLang)
  val schema = factory.newSchema(new StreamSource("Sites_types_libelles.xsd"))
  val validator = schema.newValidator()
  validator.validate(new StreamSource(code_xml.toString))
  true
}) catch {
  case t:Throwable => false
}
}



}

object ElémentXML {

def apply(fichier: String) {

  try{
  val xml_chargé = xml.XML.loadFile(fichier)
  Some(new ElémentXML(xml_chargé))
  }catch{
    case e:Throwable => None
  }
}
}

}

and here is the code for the app using this class:

val xml1:ElémentXML = ElémentXML("app/models/exemple_bon.xml")
xml1 must not beEqualTo(None)

the error is:

type mismatch; found : String("app/models/exemple_bon.xml") required: 
 scala.xml.Elem

I simply don't understand this error(and how I can remove this).

thanks!


Solution

  • Your apply method is a procedure. Amend it to apply(fichier: String): ElémentXML = ....

    The overload with the synthetic case apply is resolved by the expected type.

    This why procedure syntax will be deprecated:

    apm@mara:~/tmp$ scala -Xfuture -deprecation
    Welcome to Scala version 2.11.0-20140129-135431-0e578e6931 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala> def f() { }
    <console>:1: warning: Procedure syntax is deprecated. Convert procedure `f` to method by adding `: Unit =`.
           def f() { }
                   ^
    <console>:7: warning: Procedure syntax is deprecated. Convert procedure `f` to method by adding `: Unit =`.
           def f() { }
                   ^
    f: ()Unit
    

    One curious effect of this is the last line works by value discard:

    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    case class C(c: Int)
    object C {
    def apply(s: String): Unit = C(s.toInt)
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class C
    defined object C
    
    scala> C(4)
    res2: C = C(4)
    
    scala> C("4")
    
    scala> val x: C = C(4)
    x: C = C(4)
    
    scala> val x: C = C("4")
    <console>:11: error: type mismatch;
     found   : String("4")
     required: Int
           val x: C = C("4")
                        ^
    
    scala> val x: Unit = C("4")
    x: Unit = ()
    
    scala> val x: Unit = C(4)  // works silently
    x: Unit = ()