4

Not using operators makes my code obscure.

(aNumber / aNother) * count

is better than

aNumber.divideBy(aNother).times(count)

After 6 months of not writing a single comment I had to write a comment to the simple operation above. Usually I refactor until I don't need comment. And this made me realize that it is easier to read and perceive math symbols and numbers than their written forms.

For example

TWENTY_THOUSAND_THIRTEEN.plus(FORTY_TWO.times(TWO_HUNDERED_SIXTY_ONE))

is more obscure than

20013 + 42*261

So do you know a way to get rid of obscurity while not using operator overloading in Java?

Update: I did not think my exaggeration on comments would cause such trouble to me. I am admitting that I needed to write comment a couple of times in 6 months. But not more than 10 lines in total. Sorry for that.

Update 2: Another example:

budget.plus(bonusCoefficient.times(points))

is more obscure than

budget + bonusCoefficient * points

I have to stop and think on the first one, at first sight it looks like clutter of words, on the other hand, I get the meaning at first look for the second one, it is very clear and neat. I know this cannot be achieved in Java but I wanted to hear some ideas about my alternatives.

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
nimcap
  • 10,062
  • 15
  • 61
  • 69
  • 5
    This is not really a question about operator overloading (which java does not really support). More of a operators vs. method chaining question... – serg10 Oct 16 '09 at 12:03
  • 8
    "After 6 months of not writing a single comment" indicates you have much bigger problems than lack of operator overloading. – Fredrik Oct 16 '09 at 12:23
  • 1
    comments are usually a sign of an insecure or bad programmer. comments also go out of date very quickly; try doing a refactor or five and tell me how accurate those comments are. the code, however, is always up to date. – geowa4 Oct 16 '09 at 12:40
  • @Frederik: I guess you missed this: "Usually I refactor until I don't need comment." – nimcap Oct 16 '09 at 12:50
  • 4
    @geowa4 (and @nimcap): I can assure you my comments are not because I am insecure or bad in any way but mostly because in the real world you cannot always trust anyone else working with the code to be equally clever or equally knowledgeable about valid input and expected output of things. Refactoring until the code doesn't need comments is subjective because not everyone will share your view of the need. At the end of the day writing comments (where needed) is not something I do for myself, it is more of a courtesy to your peers and followers to make their life easier. – Fredrik Oct 16 '09 at 12:57
  • +1 @Fredrik that was refreshing, I'd work with you any day. Developers need a lot more modesty about the quality of their code, and a little more skepticism about the ability of others to understand what you did. Also, "lets refactor everything" is completely impractical in most businesses i've worked at. If i went around changing API's, even if it improved comprehension, i would mostly likely be fired; however I can easily comment something that is obtuse and would help my colleagues. – reccles Oct 16 '09 at 13:06
  • http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.html – geowa4 Oct 16 '09 at 13:21
  • 1
    @geowa4 I agree with that blog, excessive commenting is bad. However no-commenting is worse. Also, OO coding pretty much requires it if you use inheritance. Try extending a core java class correctly without reading the javadocs. I guarantee you will have a bug. – reccles Oct 16 '09 at 13:35
  • To be honest, I hardly needed comments while writing Java, in other cases, like configuration, sql, etc. files, I cannot do without comments. To be honest I exaggerated a little bit, I needed to comment a couple of times in some situations, but not in situations like this one. – nimcap Oct 16 '09 at 14:14
  • `TWENTY_THOUSAND_THIRTEEN.plus(FORTY_TWO.times(TWO_HUNDERED_SIXTY_ONE))` is indeed a lot more obscure than `20031 + 42*261`... and they're not equivalent, either. – Michael Myers Oct 16 '09 at 14:23
  • Am I the only one that thinks the opposite, that the operators (and their implicit order of execution) are MORE obscure than method chaining? Perhaps it has something to do with the nature of the projects I work on, but I typically do not deal with magic numbers, but with variables. – Steve Reed Oct 16 '09 at 14:25
  • Clean Code has a nice chapter about javadoc. I think it says all there is to know and do. –  Oct 16 '09 at 14:29
  • @Steve: I do not deal with magic numbers either, but there is lots of financial operations happening in system. And besides I write lots of tests (mostly unit), in tests I use actual (magic) numbers, and this makes it obscure. – nimcap Oct 16 '09 at 14:32
  • @mmyers: Good eye - it took me a few minutes, even with your comment, before I saw the typo in 20031. – Lawrence Dol Oct 16 '09 at 17:52
  • code show HOW, not WHY. The WHY must be left in a comment. – Thorbjørn Ravn Andersen Apr 04 '10 at 18:23
  • @Steeve Reed : Yes, you are. Most people learned to use `+`, `-`, `(`, `)` and other operators in school, and still feel quite confortable using that notation. It's called mathematics... ^_^ ... If you want comparisons of code with (C++) and without (Java) operators, feel free to look at my answer at: http://stackoverflow.com/questions/77718/java-operator-overload/194889#194889 – paercebal Jul 20 '11 at 20:52

10 Answers10

3

I had a while ago a similar requirement for using BigInteger. It depends what kind of performance sacrifice you want to do:

For the test code ( no performance requirement ) I created a parser:

Parser.execute("20031 + 42*261");

For the production code I tried to use a clever builder:

ExpressionBuilder e = new ExpressionBuilder();
e.add(20031,e.mul(42,261)).solve();

But at the end of the day, people tends to become quite used to dumb code and even prefer it: you don't have operator overload in jave so live with it and don't try to create "clever" abstraction.

BigInteger a = new BigInteger(20031);
BigInteger b = new BigInteger(42);
BigInteger a = new BigInteger(261);

BigInteger res = a.plus(b.times(c));

Anyway, check whatever works with your team.

EDIT: I didn't comment specifically on your example. But obviously calling 42,FORTY_TWO is not making the code very clear regardless your approach. Chosing proper name for the constant goes a long way clarifying the code:

BigInteger dailyOperatingCost = OFFICE_RENTAL.plus( CONTRACTOR_NUMBER.times(CONTRACTOR_RATE);
vdr
  • 958
  • 6
  • 7
2

You could use java-oo plugin for Java compiler.

mart
  • 2,537
  • 1
  • 15
  • 13
2

I think we all can be very happy, that operator overloading is not supported at all in java.

Frame myFrame = new Frame() + myButton + new JList() / new Separator() - 50;

Who wants to maintain such thing?

  • yes I know operator overloading can be abused, but sometimes that is the right thing you need. Any feature can be abused nonetheless. – nimcap Oct 16 '09 at 14:30
  • 2
    This is a fallacious argument... it's like saying that you're very happy not to have a driver's license because driving a car can kill you. Any powerful language feature can be abused... – Jesper Oct 16 '09 at 14:56
  • 2
    The real advantage is that *others* don't have a driving license to kill me. One advantages of Java is that it lacks many dangerous features. – starblue Oct 18 '09 at 08:44
  • 2
    @starblue: `One advantages of Java is that it lacks many dangerous features` I agree. My nephew has small wheels at the sides of his bike to avoid falling. He, too, likes it better than all those dangerous bicycles grown-up people tend to use fearlessly. More seriously, operator overload are **not** a major (or even a minor) source of bugs in C++. In fact, despite Gosling's belief, the major sources of bugs in C++ are C-related (C array overflow, malloc-ed allocations leaked, etc.). Operator overload makes the code clearer, nothing more, nothing less, and is as dangerous as any other function. – paercebal Jul 20 '11 at 20:59
1

In Java just get over it, and use the method names as BigInteger as a standard so you get used to them.

Or take a look at Scala.

At least that's what I do.

starblue
  • 55,348
  • 14
  • 97
  • 151
1

I like vdr's idea about the language. But you can skip on parsing and build a really simple eval. Here's a stack based eval. Put together in 15 min, and far from perfect, but you get the idea.

import java.util.*;
import java.math.BigInteger;

public class BigEval {

  private static abstract class Op{
    abstract void apply(LinkedList<BigInteger> stack);
  }

  private static Map<Character, Op> charToOp = new HashMap<Character, Op>();

  static {
    Op plus = new Op() {
      void apply(LinkedList<BigInteger> stack) { stack.push(stack.pop().add(stack.pop())); }
    };
    Op mult = new Op() {
      void apply(LinkedList<BigInteger> stack) { stack.push(stack.pop().multiply(stack.pop())); }
    };
    Op dup = new Op() {
      void apply(LinkedList<BigInteger> stack) { stack.push(stack.peek()); }
    };

    charToOp.put('+', plus);
    charToOp.put('*', mult);
    charToOp.put('d', dup);
  }


  public static BigInteger eval(Object ... expression){
    return eval(new LinkedList(Arrays.asList(expression)), new LinkedList());
  }

  private static BigInteger eval(LinkedList expression, LinkedList<BigInteger> stack){
    while (expression.size()>0){
      Object next = expression.pop();
      if (next instanceof BigInteger){
        stack.push((BigInteger)next);
      } else if (next instanceof Number) {
        stack.push(BigInteger.valueOf(((Number)next).longValue()));
      } else {
        charToOp.get(next).apply(stack);
      }
    }
    return stack.pop();
  }

  public static void main(String[] args) {
    System.out.println(
      BigEval.eval(3, 4, '+', 5, '*')
    );
  }

} // end of class
Mark Bolusmjak
  • 23,606
  • 10
  • 74
  • 129
  • I like this idea. Your solution reminds me of some of the simple, elegant solutions from my CS classes so long ago. It is easy to get distracted by 'XML-this' and 'web-that' of today. I think your solution would be ultimately more readable and maintainable as it is a general-purpose solution to the scale of this problem. – monceaux Oct 16 '09 at 20:18
0

You cannot overload operators in Java, and there's no way around it.

You could use a Java-like alternative JVM language. Groovy is one that is probably closer to Java itself than other JVM languages. See Operator overloading in Groovy.

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • Scala can be written in a near identical manner to Java, while allowing you to branch out into functional programming. Also, James Strachan (creator of Groovy) said that if some had shown him "Programming in Scala" in 2003, he would never have created Groovy . – geowa4 Oct 16 '09 at 12:25
0

There is no way to overload operator in Java. Why don't you switch to C#?! =)

Or try to write shorter named methods in Java:

aNumber.div(aNother).mul(count)
Cipi
  • 11,055
  • 9
  • 47
  • 60
  • switching to C# is not feasible in most applications or most workplaces. especially when there are other jvm languages that can integrate with your existing code. – geowa4 Oct 16 '09 at 12:41
0

If you're just dealing with numeric values, the standard wrapper classes (Integer, Double, etc) will be automatically unboxed to their primitive types when used in expressions. The following is perfectly valid:

  Integer five = new Integer(5);

  Integer ten = new Integer(10);

  System.out.println(five * ten);

  System.out.println(ten / five);
Fredrick Pennachi
  • 832
  • 1
  • 8
  • 17
0

The easiest way is probably by assigning subexpressions to variable with meaningful names.

   discriminant = b.times(b).plus(four.times(a).times(c));

You may even want to calculate bsquared and ac4 (fourac?) too.

This functions as meaningful comments plus it keeps the length of your source lines down.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
0

I was like you, I now find the class names to be a handy documentation so as to do self-documenting code. You're gonna have to work your own way out of the difficulties consequent to the comment markers as that is established practice in Java. As for where your intentions seeks, what that ends up with is sort of a cloud. Now if I were anywhere close to information that has to be protected, the absolute last thing I want is to have customer's data being passed into a cloud by small, tight code. I expand everything, working from post-processor in C and working in native calls for anything in Java that I am actually intent on protecting.

What I see in your original post, though not to take sides, is something where a rather massive code effort can be called thus:

doIt();

Which woe be unto the damnned, is not only asking for candy-code and doing it, but for sure would go nowhere at massive parallel systems running critical code unless you wrote both the compiler and the security domain on which the above runs. I am not being, nor intend on being, even slightly facetious - trust is something you read about on the 6-pm news, and is loved by your competitors who want to take your lunch away from you. There are dozens of languages that do what you ask, why are you asking it in a Java discussion?

Maybe it's time to intro on a linguistic that does that == there are no shortage of api's and supporters thereof that do that. Code should be self-documenting, for Java that's class name as what it does name.

Nicholas Jordan
  • 638
  • 3
  • 6