All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalautils.TripleEquals.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2001-2013 Artima, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.scalautils

import TripleEqualsSupport._

/**
 * Provides === and !== operators that return Boolean, delegate the equality determination
 * to an Equality type class, and require no relationship between the types of the two values compared. 
 * 
 * 
* Recommended Usage: * Trait TripleEquals is useful (in both production and test code) when you need determine equality for a type of object differently than its * equals method: either you can't change the equals method, or the equals method is sensible generally, but * you are in a special situation where you need something else. If you also want a compile-time type check, however, you should use one * of TripleEquals sibling traits: * ConversionCheckedTripleEquals or TypeCheckedTripleEquals. *
* *

* This trait will override or hide implicit methods defined by its sibling traits, * ConversionCheckedTripleEquals or TypeCheckedTripleEquals, * and can therefore be used to temporarily turn of type checking in a limited scope. Here's an example, in which TypeCheckedTripleEquals will * cause a compiler error: *

* *
 * import org.scalautils._
 * import TypeCheckedTripleEquals._
 *
 * object Example {
 *
 *   def cmp(a: Int, b: Long): Int = {
 *     if (a === b) 0       // This line won't compile
 *     else if (a < b) -1
 *     else 1
 *   }
 *
 *  def cmp(s: String, t: String): Int = {
 *    if (s === t) 0
 *    else if (s < t) -1
 *    else 1
 *  }
 * }
 * 
* * Because Int and Long are not in a subtype/supertype relationship, comparing 1 and 1L in the context * of TypeCheckedTripleEquals will generate a compiler error: *

* *
 * Example.scala:9: error: types Int and Long do not adhere to the equality constraint selected for
 * the === and !== operators; they must either be in a subtype/supertype relationship, or, if
 * ConversionCheckedTripleEquals is in force, implicitly convertible in one direction or the other;
 * the missing implicit parameter is of type org.scalautils.Constraint[Int,Long]
 *     if (a === b) 0      // This line won't compile
 *           ^
 * one error found
 * 
* *

* You can “turn off” the type checking locally by importing the members of TripleEquals in * a limited scope: *

* *
 * package org.scalautils.examples.tripleequals
 * 
 * import org.scalautils._
 * import TypeCheckedTripleEquals._
 * 
 * object Example {
 * 
 *   def cmp(a: Int, b: Long): Int = {
 *     import TripleEquals._
 *     if (a === b) 0
 *     else if (a < b) -1
 *     else 1
 *   }
 *
 *  def cmp(s: String, t: String): Int = {
 *    if (s === t) 0
 *    else if (s < t) -1
 *    else 1
 *  }
 * }
 * 
* *

* With the above change, the Example.scala file compiles fine. Type checking is turned off only inside the first cmp method that * takes an Int and a Long. TypeCheckedTripleEquals is still enforcing its type constraint, for example, for the s === t * expression in the other overloaded cmp method that takes strings. *

* *

* Because the methods in TripleEquals (and its siblings)override all the methods defined in * supertype TripleEqualsSupport, you can achieve the same * kind of nested tuning of equality constraints whether you mix in traits, import from companion objects, or use some combination of both. *

* *

* In short, you should be able to select a primary constraint level via either a mixin or import, then change that in nested scopes * however you want, again either through a mixin or import, without getting any implicit conversion ambiguity. The innermost constraint level in scope * will always be in force. *

* * @author Bill Venners */ trait TripleEquals extends TripleEqualsSupport { import scala.language.implicitConversions // Inherit the Scaladoc for these methods implicit override def convertToEqualizer[T](left: T): Equalizer[T] = new Equalizer(left) override def convertToCheckingEqualizer[T](left: T): CheckingEqualizer[T] = new CheckingEqualizer(left) override def convertToLegacyEqualizer[T](left: T): LegacyEqualizer[T] = new LegacyEqualizer(left) override def convertToLegacyCheckingEqualizer[T](left: T): LegacyCheckingEqualizer[T] = new LegacyCheckingEqualizer(left) implicit override def unconstrainedEquality[A, B](implicit equalityOfA: Equality[A]): Constraint[A, B] = new EqualityConstraint[A, B](equalityOfA) override def lowPriorityTypeCheckedConstraint[A, B](implicit equivalenceOfB: Equivalence[B], ev: A <:< B): Constraint[A, B] = new AToBEquivalenceConstraint[A, B](equivalenceOfB, ev) override def convertEquivalenceToAToBConstraint[A, B](equivalenceOfB: Equivalence[B])(implicit ev: A <:< B): Constraint[A, B] = new AToBEquivalenceConstraint[A, B](equivalenceOfB, ev) override def typeCheckedConstraint[A, B](implicit equivalenceOfA: Equivalence[A], ev: B <:< A): Constraint[A, B] = new BToAEquivalenceConstraint[A, B](equivalenceOfA, ev) override def convertEquivalenceToBToAConstraint[A, B](equivalenceOfA: Equivalence[A])(implicit ev: B <:< A): Constraint[A, B] = new BToAEquivalenceConstraint[A, B](equivalenceOfA, ev) override def lowPriorityConversionCheckedConstraint[A, B](implicit equivalenceOfB: Equivalence[B], cnv: A => B): Constraint[A, B] = new AToBEquivalenceConstraint[A, B](equivalenceOfB, cnv) override def convertEquivalenceToAToBConversionConstraint[A, B](equivalenceOfB: Equivalence[B])(implicit ev: A => B): Constraint[A, B] = new AToBEquivalenceConstraint[A, B](equivalenceOfB, ev) override def conversionCheckedConstraint[A, B](implicit equivalenceOfA: Equivalence[A], cnv: B => A): Constraint[A, B] = new BToAEquivalenceConstraint[A, B](equivalenceOfA, cnv) override def convertEquivalenceToBToAConversionConstraint[A, B](equivalenceOfA: Equivalence[A])(implicit ev: B => A): Constraint[A, B] = new BToAEquivalenceConstraint[A, B](equivalenceOfA, ev) } /** * Companion object to trait TripleEquals that facilitates the importing of TripleEquals members as * an alternative to mixing it in. One use case is to import TripleEquals members so you can use * them in the Scala interpreter: * *

 * $ scala -classpath scalatest.jar
 * Welcome to Scala version 2.10.0
 * Type in expressions to have them evaluated.
 * Type :help for more information.
 *
 * scala> import org.scalautils._
 * import org.scalautils._
 *
 * scala> import TripleEquals._
 * import TripleEquals._
 *
 * scala> 1 + 1 === 2
 * res0: Boolean = true
 * 
*/ object TripleEquals extends TripleEquals




© 2015 - 2024 Weber Informatics LLC | Privacy Policy