Except when not having it is the worst. Working with BigDecimal in Java is hell because it does not have operative overloading, meaning while you avoid
boostfs::path path("/some/path");
path /= "yourfile.txt";
you get saddled with bullshit like x.add(x.add(ONE).pow(2).subtract(x)) x.add(x.add(ONE).pow(2).subtract(x))
Especially because sometimes it is difficult to decide whether you should have x.foo(y) or y.foo(x). However, add(x, sub(pow(add(x, ONE), 2), x))
Is perfectly acceptable in my opinion (add some indentation if it's difficult to read). As long as you can pass parameters and return values without tricks (ie. passing pointers), this is quite nice. You should even be able to do this in Java with "import static". Or C++ with function overloading.I'm definitely not a fan of C++ -style operator overloading, where you only have a finite amount of operators with set precedence/associativity and then they get overloaded to meanings that the symbols don't convey. On the other hand, I'm not sure what to think of Haskell either (where you can define arbitrary operators, like >>=, <+> or <$>). It's not as limited as C++, but there are some quite nasty examples that have gone overboard with operators.
Overall, it seems like operator overloading adds a lot of complexity to a language but the benefit is arguable.
I comletelly agree with this, it is very confusing API.
You should even be able to do this in Java with "import static"
Yep, you should define a static methods add, sub, pow etc with BigDecimal parameters and then use import static.
Something along
class BigDecimalMath { public static BigDecimal add(BigDecimal x1, BigDecimal x2) { return x1.add(x2); } }
Also JVM JIT would very likely inline such code, so you should not really worry about an added method call.
BiFunction<BigDecimal, BigDecimal, BigDecimal> add = BigDecimal::add; add(x, y);
Unfortunately you have to do:
add.apply(x, y);
Which is kind of cumbersome.
Unfortunately they brought something completely different in the name of Default Methods, and that was in my opinion not needed.
func SameSideOfTriangle<N>(p0 Point2D<N>, p1 Point2D<N>, a Point2D<N>, b Point2D<N>) bool where N: Number {
ba := Point2D(b.x.Sub(a.x), b.y.Sub(a.y))
p0a := Point2D(p0.x.Sub(a.x), p0.y.Sub(a.y))
p1a := Point2D(p1.x.Sub(a.x), p1.y.Sub(a.y))
cp0 := ba.x.Mul(p0a.y).Sub(p0a.x.Mul(ba.y))
cp1 := ba.x.Mul(p1a.y).Sub(p1a.x.Mul(ba.y))
dot := cp0.x.Mul(cp1.x).Add(cp0.y.Mul(cp1.y))
return dot >= 0
}
Versus: func SameSideOfTriangle<N>(p0 Point2D<N>, p1 Point2D<N>, a Point2D<N>, b Point2D<N>) bool where N: Number {
ba := Point2D(b.x - a.x, b.y - a.y)
p0a := Point2D(p0.x - a.x, p0.y - a.y)
p1a := Point2D(p1.x - a.x, p1.y - a.y)
cp0 := ba.x * p0a.y - p0a.x * ba.y
cp1 := ba.x * p1a.y - p1a.x * ba.y
dot := cp0.x * cp1.x + cp0.y * cp1.y
return dot >= 0
}Genuinely asking: Why does this function need to be generic over Numbers? Couldn't you implement it once or twice for whatever actually-numeric types you need? How many different Point2D template instantiations do you actually have?
And that's only a small function (only one part of what's needed to check point-triangle intersection!) Copying and pasting e.g. Sutherland-Hodgman clipping or 4D/5D matrix math would get unsustainable quickly.
Granted, you then have the problem of having to deal with overflow on different types, but that's just one of the ocean liner of problems you've signed up for if you're working in the graphics space. May the odds be ever in your favor. ;)
x + ((x + ONE).pow(2) - x)
or x + (pow(x + ONE) - x)On the contrary, when all you have is a couple of examples that aren't even that bad and a slippery slope argument, you are on very thin ground, rhetorically speaking.
path += '/' + 'yourfile.txt';
It's also entirely possible that I'd already subconsciously read ahead and so knew that it couldn't have possibly been division.
This is one of those "well intentioned" features that turns into a quagmire in practice.