Class/Object

com.thoughtworks.feature

Constructor

Related Docs: object Constructor | package feature

Permalink

final class Constructor[F] extends AnyVal

An implicit value for dynamically creating classes and traits, especially dynamic mixins.

Usage

libraryDependencies += "com.thoughtworks.feature" %% "constructor" % "latest.release"
trait A
trait B

def makeAWithB()(implicit constructor: Constructor[() => A with B]): A with B = {
  constructor.newInstance()
}

val ab: A with B = makeAWithB()

Motivation

This feature is useful for library authors. A library author may ask his user to create a trait type, then dynamically mix-in it with the features provided by the library.

Suppose you are creating a DSL that compiles to JavaScript.

You want your DSL is extensible. For example, the DSL users should be able to create custom binary operators.

With the help of Constructor.scala, you can put the boilerplate code into a private class BinaryOperator:

trait Ast

object Ast {

  class Literal(val n: Int) extends Ast {
    override final def compile(): String = n.compile()
  }

  private[Ast] abstract class BinaryOperator(leftHandSide: Ast, rightHandSide: Ast) extends Ast {
    protected def symbol: String
    override final def compile() = s"($leftHandSide $symbol $rightHandSide)"
  }

  def binaryOperator[T](leftHandSide: Ast, rightHandSide: Ast)(
    implicit constructor: Constructor[(Ast, Ast) => BinaryOperator with T]): BinaryOperator with T = {
    constructor.newInstance(leftHandSide, rightHandSide)
  }

}

The users only need a very simple implementation for their custom binary operators.

import Ast._

trait Plus {
  protected final def symbol = "+"
}

trait Minus {
  protected final def symbol = "-"
}

val myAst = binaryOperator[Plus](
  new Literal(1),
  binaryOperator[Minus](
    new Literal(3),
    new Literal(5)
  )
)

print(myAst.compile()) // Output: "(1 + (3 - 5))"

An alternative approach

There is another approach to integrate partial implementation from users: asking users to provide custom callback functions or type classes.

However, the callback functions or type classes approach will create additional object instances and additional references for each instance at run-time. On the other hand, the Constructor.scala approach create classes at compile-time and no additional run-time references. As a result, at run-time, Constructor.scala approach will consume less memory, and performs less indirect access on memory.

Author:

杨博 (Yang Bo) <[email protected]>

Source
Constructor.scala
Linear Supertypes
Type Hierarchy
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. Constructor
  2. AnyVal
  3. Any
Implicitly
  1. by any2stringadd
  2. by StringFormat
  3. by Ensuring
  4. by ArrowAssoc
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. All

Instance Constructors

  1. new Constructor(newInstance: F)

    Permalink

Value Members

  1. final def !=(arg0: Any): Boolean

    Permalink
    Definition Classes
    Any
  2. final def ##(): Int

    Permalink
    Definition Classes
    Any
  3. def +(other: String): String

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to any2stringadd[Constructor[F]] performed by method any2stringadd in scala.Predef.
    Definition Classes
    any2stringadd
  4. def ->[B](y: B): (Constructor[F], B)

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to ArrowAssoc[Constructor[F]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc
    Annotations
    @inline()
  5. final def ==(arg0: Any): Boolean

    Permalink
    Definition Classes
    Any
  6. final def asInstanceOf[T0]: T0

    Permalink
    Definition Classes
    Any
  7. def ensuring(cond: (Constructor[F]) ⇒ Boolean, msg: ⇒ Any): Constructor[F]

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to Ensuring[Constructor[F]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  8. def ensuring(cond: (Constructor[F]) ⇒ Boolean): Constructor[F]

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to Ensuring[Constructor[F]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  9. def ensuring(cond: Boolean, msg: ⇒ Any): Constructor[F]

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to Ensuring[Constructor[F]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  10. def ensuring(cond: Boolean): Constructor[F]

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to Ensuring[Constructor[F]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  11. def formatted(fmtstr: String): String

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to StringFormat[Constructor[F]] performed by method StringFormat in scala.Predef.
    Definition Classes
    StringFormat
    Annotations
    @inline()
  12. def getClass(): Class[_ <: AnyVal]

    Permalink
    Definition Classes
    AnyVal → Any
  13. final def isInstanceOf[T0]: Boolean

    Permalink
    Definition Classes
    Any
  14. val newInstance: F

    Permalink
  15. def toString(): String

    Permalink
    Definition Classes
    Any
  16. def [B](y: B): (Constructor[F], B)

    Permalink
    Implicit information
    This member is added by an implicit conversion from Constructor[F] to ArrowAssoc[Constructor[F]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc

Inherited from AnyVal

Inherited from Any

Inherited by implicit conversion any2stringadd from Constructor[F] to any2stringadd[Constructor[F]]

Inherited by implicit conversion StringFormat from Constructor[F] to StringFormat[Constructor[F]]

Inherited by implicit conversion Ensuring from Constructor[F] to Ensuring[Constructor[F]]

Inherited by implicit conversion ArrowAssoc from Constructor[F] to ArrowAssoc[Constructor[F]]

Ungrouped