Object-oriented or functional? Why not both with Scala?

Image for post
Image for post
I think this is a city bike, though the seat seems kind of high. Photo by Mikkel Bech on Unsplash
    List<MyCustomObject> myCustObjList = new ArrayList<>();
Image for post
Image for post
Ukulele. Its four strings are generally tuned G-C-E-A. Photo by Samuel Ramos on Unsplash
public abstract class QuadraticRing implements IntegerRing {    // ...several lines omitted...    public abstract double getRadSqrt();    // ...several lines omitted...}
public class RealQuadraticRing extends QuadraticRing {    // ...several lines omitted...    private double realRadSqrt;    @Override
public double getRadSqrt() {
return this.realRadSqrt;
}
// ...several lines omitted...}
public class ImaginaryQuadraticRing extends QuadraticRing {    // ...several lines omitted...    @Override
public double getRadSqrt() {
String exceptionMessage = "Since the radicand " +
this.radicand + " is negative, this operation" +
" requires an object that can represent a" +
" purely imaginary number.";
throw new UnsupportedOperationException(exceptionMessage);
}
// ...several lines omitted...}
scala> 1729.getClass
res0: Class[Int] = int
scala> "Hello, World!".getClass
res1: Class[_ <: String] = class java.lang.String
scala> (Math.sqrt _).getClass
res2: Class[_ <: Double => Double] = class $$Lambda$1097/1998603857
package fractions;public class Fraction {

private final long fractNumer;
private final long fractDenom;

public Fraction plus(Fraction addend) {
long interNumerA = this.fractNumer * addend.fractDenom;
long interNumerB = addend.fractNumer * this.fractDenom;
long newNumer = interNumerA + interNumerB;
long newDenom = this.fractDenom * addend.fractDenom;
return new Fraction(newNumer, newDenom);
}
\\ ...other arithmetic functions omitted... \\ ...constructor omitted...}
scala> val oneHalf = new fractions.Fraction(1, 2)
oneHalf: fractions.Fraction = 1/2
scala> val twoThirds = new fractions.Fraction(2, 3)
twoThirds: fractions.Fraction = 2/3
scala> oneHalf.plus(twoThirds)
res3: fractions.Fraction = 7/6
scala> oneHalf.times(twoThirds)
res5: fractions.Fraction = 1/3
scala> oneHalf + twoThirds
<console>:14: error: type mismatch;
found : fractions.Fraction
required: String
oneHalf + twoThirds
^
scala> oneHalf * twoThirds
<console>:14: error: value * is not a member of fractions.Fraction
oneHalf * twoThirds
^
package fractionsclass Fraction(numerator: Long, denominator: Long = 1L) {
if (fractDenom == 0) {
throw new IllegalArgumentException("fractDenom 0 invalid.")
}
long gcdNumDen = euclideanGCD(numerator, denominator)
if (fractDenom < 0) {
gcdNumDen = gcdNumDen * -1
}
val fractNumer = numerator / gcdNumDen
val fractDenom = denominator / gcdNumDen
// ...toString() omitted... def +(summand: Fraction): Fraction = {
interNumerA = this.fractNumer * addend.fractDenom
interNumerB = addend.fractNumer * this.fractDenom
newNumer = interNumerA + interNumerB
newDenom = this.fractDenom * addend.fractDenom
new Fraction(newNumer, newDenom)
}
// ...several lines omitted...}
scala> val oneHalf = new fractions.Fraction(1, 2)
oneHalf: fractions.Fraction = 1/2
scala> val twoThirds = new fractions.Fraction(2, 3)
twoThirds: fractions.Fraction = 2/3
scala> oneHalf + twoThirds
res0: fractions.Fraction = 7/6
scala> oneHalf - twoThirds
res1: fractions.Fraction = -1/6
scala> oneHalf * twoThirds
res2: fractions.Fraction = 1/3
scala> oneHalf / twoThirds
res3: fractions.Fraction = 3/4
scala> oneHalf plus twoThirds
res6: fractions.Fraction = 7/6
scala> oneHalf.+(twoThirds)
res4: fractions.Fraction = 7/6
scala> 1 to 100
res5: scala.collection.immutable.Range.Inclusive = Range 1 to 100
scala> res5.mkString(", ")
res6: String = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100
scala> res5.map(4 _ + 1)
<console>:13: error: _ must follow method; cannot follow Int(4)
res5.map(4 _ + 1)
^
scala> res5.map(4 * _ + 1)
res8: scala.collection.immutable.IndexedSeq[Int] = Vector(5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233, 237, 241, 245, 249, 253, 257, 261, 265, 269, 273, 277, 281, 285, 289, 293, 297, 301, 305, 309, 313, 317, 321, 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401)
scala> def recip(n: Int): fractions.Fraction = new fractions.Fraction(1, n)
recip: (n: Int)fractions.Fraction
scala> recip(3) // Just checking that it works
res9: fractions.Fraction = 1/3
scala> res8.map(recip)
res10: scala.collection.immutable.IndexedSeq[fractions.Fraction] = Vector(1/5, 1/9, 1/13, 1/17, 1/21, 1/25, 1/29, 1/33, 1/37, 1/41, 1/45, 1/49, 1/53, 1/57, 1/61, 1/65, 1/69, 1/73, 1/77, 1/81, 1/85, 1/89, 1/93, 1/97, 1/101, 1/105, 1/109, 1/113, 1/117, 1/121, 1/125, 1/129, 1/133, 1/137, 1/141, 1/145, 1/149, 1/153, 1/157, 1/161, 1/165, 1/169, 1/173, 1/177, 1/181, 1/185, 1/189, 1/193, 1/197, 1/201, 1/205, 1/209, 1/213, 1/217, 1/221, 1/225, 1/229, 1/233, 1/237, 1/241, 1/245, 1/249, 1/253, 1/257, 1/261, 1/265, 1/269, 1/273, 1/277, 1/281, 1/285, 1/289, 1/293, 1/297, 1/301, 1/305, 1/309, 1/313, 1/317, 1/321, 1/325, 1/329, 1/333, 1/337, 1/341, 1/345, 1/349, 1/353, 1/357, 1/361, 1/365, 1/369, 1/373, 1/377, 1/381, 1/385, 1/389, 1/393, 1/397, 1/401)
scala> val four = new fractions.Fraction(4)
four: fractions.Fraction = 4
scala> val one = new fractions.Fraction(1)
one: fractions.Fraction = 1
scala> res10.map(four * _ + one)
res11: scala.collection.immutable.IndexedSeq[fractions.Fraction] = Vector(9/5, 13/9, 17/13, 21/17, 25/21, 29/25, 33/29, 37/33, 41/37, 45/41, 49/45, 53/49, 57/53, 61/57, 65/61, 69/65, 73/69, 77/73, 81/77, 85/81, 89/85, 93/89, 97/93, 101/97, 105/101, 109/105, 113/109, 117/113, 121/117, 125/121, 129/125, 133/129, 137/133,
141/137, 145/141, 149/145, 153/149, 157/153, 161/157, 165/161, 169/165, 173/169, 177/173, 181/177, 185/181, 189/185, 193/189, 197/193, 201/197, 205/201, 209/205, 213/209, 217/213, 221/217, 225/221, 229/225, 233/229, 237/233, 241/237, 245/241, 249/245, 253/249, 257/253, 261/257, 265/261, 269/265, 273/269, 277/273, 281/
277, 285/281, 289/285, 293/289, 297/293, 301/297, 305/301, 309/305, 313/309, 317/313, 321/317, 325/321, 329/325, 333/329, 337/333, 341/337, 345/341, 349/345, ...
scala> Integer.MIN_VALUE * Integer.MIN_VALUE
res12: Int = 0
scala> Math.abs(Integer.MIN_VALUE)
res13: Int = -2147483648
  // STUB TO FAIL THE TEST
def euclideanGCD(a: Int, b: Int, eucFn: Int => Int): Int = {
-1 // Clearly wrong value to fail the test
}
  @Test def testEuclideanGCD18N27(): Unit = {
println("gcd(-27, 18)")
val expected = 9
val actual = euclideanGCD(-27, 18, Math.abs)
assertEquals(expected, actual)
}
  def square(n: Int): Int = n * n
  def euclideanGCD(a: Int, b: Int, eucFn: Int => Int): Int = {
var currA = a
var currB = b
var tempMultiple: double
while (eucFn(currB) != 0) {
tempMultiple = Math.floor(currA / currB) * currB
currRemainder = currA - tempMultiple
if (eucFn(currRemainder) >= eucFn(currB)) {
val excMsg = "Z is not Euclidean for the function " +
eucFn.getClass.getName
throw new NonEuclideanDomainException(excMsg, a, b, eucFn)
}
currA = currB
currB = currRemainder
}
currA
}
  def invalidFunctionF(n: Int): Int = -3  def invalidFunctionG(n: Int): Int = 3  @Test(expected = classOf[IllegalArgumentException])
def testEuclideanGCDThrowsIAE(): Unit = {
euclideanGCD(-27, 18, invalidFunctionF)
}
@Test(expected = classOf[NonEuclideanDomainException])
def testEuclideanGCDThrowsNEDE(): Unit = {
euclideanGCD(-27, 18, invalidFunctionG)
}
scala> class NonEuclideanDomainException(exceptionMessage: String, a: Int, b: Int, eucFn: Int => Int) extends Exception(exceptionMessage: String) { }
defined class NonEuclideanDomainException
scala> calculators.NTFC.euclideanGCD(-27, 18, invalidFunctionF)
java.lang.IllegalArgumentException: The function $$Lambda$1081/1587485260 is not a valid Euclidean function because it sometimes returns negative values.
at calculators.NTFC$.euclideanGCD(NTFC.scala:41)
... 28 elided
scala> calculators.NTFC.euclideanGCD(-27, 18, invalidFunctionG)
exceptions.NonEuclideanDomainException: Z is not Euclidean for the function f = $$Lambda$1087/1004308853 since f(-9) = 3 but f(18) = 3.
at calculators.NTFC$.euclideanGCD(NTFC.scala:48)
... 28 elided
scala> def alternateFunctionF(n: Int): Int = Math.abs(n) + (if (n < -1 || n > 1) 1 else 0)
alternateFunctionF: (n: Int)Int
scala> euclideanGCD(-27, 18, alternateFunctionF)
res14: Int = 9
scala> calculators.NTFC.euclideanGCD(46341, 46342, square)
java.lang.IllegalArgumentException: The function $$Lambda$1107/1806440863 is not a valid Euclidean function because it sometimes returns negative values.
at calculators.NTFC$.euclideanGCD(NTFC.scala:41)
... 28 elided
Image for post
Image for post
Photo by Sander Crombach on Unsplash

is a composer and photographer from Detroit, Michigan. He has been working on a Java program to display certain mathematical diagrams.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store