2

Consider the "constant" value: DefaultEncoding. Typically we would add it to the companion object:

object Strlen {
  val DefaultEncoding = "ISO-8859-1"
  ..
}

However, we are compelled to avoid the use of a companion object because Strlen is required to be a case class to correspond to code structures/conventions in a significant existing codebase:

case class Strlen(child: Expression, encoding : Expression) extends UnaryExpression with LengthExpression {

  val DefaultEncoding = "ISO-8859-1"    // This will not be isible in the following constructor

  def this(child: Expression) = this(child, new Literal(DefaultEncoding, StringType))

So then would there be any way to achieve compartmentalization of the DefaultEncoding 'constant' within the case class?

Update From suggestion by wingedsubmariner, I tried the following within the case class:

def DefaultEncoding = "ISO-8859-1"

However it does not compile

[info] Compiling 1 Scala source to /shared/spark-master/sql/catalyst/target/scala-2.10/classes...
[error] /shared/spark-master/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/stringOperations.scala:253: not found: value DefaultEncoding
[error]   def this(child: Expression) = this(child, new Literal(/* StrConstants. */DefaultEncoding, StringType))
[error]       
WestCoastProjects
  • 58,982
  • 91
  • 316
  • 560
  • You can't have constants inside a case class, the naming should really be lower camel case `defaultEncoding`. – samthebest Jul 24 '14 at 19:43
  • @samthebest Yes I am aware of both of those - that was the point of this question to ask how to work this. Please point out how to resolve the issue instead. – WestCoastProjects Jul 24 '14 at 21:11

2 Answers2

4

Writing a custom companion object for a case class won't prevent the compiler from providing the default helper methods for the case class.

trait Expression
trait UnaryExpression extends Expression
trait LengthExpression extends Expression

trait Typ
case object StringType extends Typ

case class Literal(val encoding: String, val typ: Typ) extends Expression

case class StrLen(child: Expression, encoding: Expression) extends UnaryExpression with LengthExpression {
  def this(child: Expression) = this(child, new Literal(StrLen.DefaultEncoding, StringType))
}

object StrLen {
  val DefaultEncoding = "ISO-8859-1"
  def apply(child: Expression): StrLen = apply(child, new Literal(StrLen.DefaultEncoding, StringType))
}

case object ExampleExpression extends Expression

println(StrLen(ExampleExpression))
// --> StrLen(ExampleExpression,Literal(ISO-8859-1,StringType))
println(new StrLen(ExampleExpression))
// --> StrLen(ExampleExpression,Literal(ISO-8859-1,StringType))
def isProduct[T <: Product] {}
isProduct[StrLen]

The default apply is still provided by the compiler (and used in def apply(child: Expression), StrLen still extends Product and toString still does the right thing. The custom constructor def this(child: Expression) is probably unnecessary, as you can use the single-parameter apply instead.

Utaal
  • 8,484
  • 4
  • 28
  • 37
  • Thanks, I am under the gun this morning but will come back to verify. Upvoted in the meantime. – WestCoastProjects Jul 24 '14 at 18:38
  • Actually writing a custom companion object does indeed remove some default helper methods, that the compiler won't add anymore. See this question: https://stackoverflow.com/q/25392422/935676 – amoebe Dec 03 '17 at 10:53
3

You can use companion objects with case classes. If you declare an object with the same name in the same compilation unit (usually the same file) it will be treated as the case class's companion object and have the usual case class companion object methods, e.g. unapply, added to it.

The other option is to declare DefaultEncoding as a def. Because field access is always done through accessors in Scala this doesn't have any performance penalty.

wingedsubmariner
  • 13,350
  • 1
  • 27
  • 52
  • I need the Product interface implementation that comes with the Case Class default Companion object - so your first suggestion is less than ideal. I do not want to code that myself as a general rule. I am trying the def suggestion now. – WestCoastProjects Jul 24 '14 at 04:17
  • According to @Utaal the product interface does work anyway. Thanks, I am under the gun this morning but will come back to verify. Upvoted in the meantime. – WestCoastProjects Jul 24 '14 at 18:38
  • 1
    Actually if you declare a custom companion object the compiler won't add some methods, e.g. `tupled` is not there. See this question https://stackoverflow.com/q/25392422/935676 – amoebe Dec 03 '17 at 10:54