This discussion is archived
2 Replies Latest reply: Jun 16, 2004 12:13 PM by 843853 RSS

Saying A means saying B

843853 Newbie
Currently Being Moderated
SAYING A MEANS SAYING B

...sooner or later. No one for quite long time don't even date to propose new language features in Java. I think this happened because authors of Java explained in detail why some features of C++ was absent in the language. One could even suppose there nothing to add to such the perfect language. This irony could be justified now when we know about changes in Java which stalking around since the first alpha version of JDK 1.5. C++ templates arrived, foreach and enums did the same. Wait you can say but Java lacks... Yes, right, yet one feature. I suppose this will be great idea if not only by means of JCP (which by the way could be proposed only by employees of the major players in Java world) but each developer could suggest what missed in the language. Personally I waited for almost five years for such opportunity and here I am.

A SAID

Why developers of Java said only A? Is it possible the authority of Bjarne Stroustrup is really great that doesn't allow to note one fact. Templating is not thorough in C++. It would be not entirely covered if will remain the same as introduces in JDK 1.5. Well, the fact is: everything is templating. At least, in human reasoning: we recognize and apply templates each day in our life. Compiler does the same. Let's consider "for".
template 'for (<init>; <cond>; <cont>) { <code> }' {

     init;
     label: {
          code;
          cont;
          if (cond) continue label;
     }

}
As the opposite to everyday life, templates as they arrived in 1.5 is quite simple (especially who knows them by C++ experience):
public interface List<E> extends Collection<E> {

     ...

     Iterator<E> iterator();

     ...

}
But moreover they offer only one part of template handling: applying. That's we take a generic type and apply it to specific class and get list of ints or Strings. This is compliant with contemporary programming languages: they all are basically template applying languages as in the case of "for". This concerns, of course, only developers of Java and not Java developers, you know. Compiler rather recognizes the "for" template and then applies it to the code. But why template recognizing isn't still proposed for Java or C++ developers? Well, basically it could make languages more extensible and this is the major threat (no one wants to get very confusing code). But on the other side we would have got the language with infinite possibilities.

Let's begin with the least of consequences of more thourough template introduction. This concerns the great and terrible programming style, approach, and pattern called Copy-Paste. Look at the following code:
JButton button = new JButton();
button.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
          a = 5;
          b = 7;
     }
});
There's a lot of code with similar definitions but what's if we invite new template definition:
template addActionListener <component, actions> {
     component.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
               actions
          }
     });
}

...

addActionListener <button> <
     a = 5;
     b = 7;
>
or even
addActionListener(button) {
     a = 5;
     b = 7;
}
Yes, this could be reduced to just method call but it not always available when, for example, we use third-party library, etc. Or, let's look for Arrays.sort and Collections.sort methods. In current alpha version of JDK 1.5 Collections.sort defined as follows:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
     Object[] a = list.toArray();
     Arrays.sort(a);
     ListIterator<T> i = list.listIterator();
     for (int j=0; j<a.length; j++) {
          i.next();
          i.set((T)a[j]);
     }
}
It's a little different from STL where sort belongs to algorithms and its parameters are just iterators which could be both array's, list's or whatever else. On the other hand, if we will look in Arrays.sort method we understand that the point of this method as for arrays is just getting nth element. That is we can define own template sort:
template sort <container, geti(i)> {
     ...
     geti(i) = geti(--n);
     ...
}
And use it as follows:
sort <a, a>;
sort <list, get(i)>;

Sometimes there is situations in which we couldn't apply no one of some advanced programming technics.
while (a > 4) {
     ... // piece of code #1
     a = doSomething();
     ... // piece of code #2
}

while (a > 5) {
     ... // piece of code #3
     a = doSomething();
     ... // piece of code #2
}
This sample ask itself for some refining but how? To define method with parameters and ifs? But this task couldn't be as simple as appears and would require many parameters. Then we have to define helper class for parameters to have the good programming style looming between lines. A long way to solution, isn't? It seems there is more elegant way.
template myWhile <value, code1> {

     while (a > value) {
          code1;
          a = doSomething();
          ... // piece of code #2     
     }

}
And using:
myWhile<4> <
     ... // piece of code #1
>

myWhile<5 <
     ... // piece of code #3
>
With thorough templating other programming patterns also has a chance to be implemented (please note createMethods[] - yes templating needs list context - that's my belief).
tempate AbstractFactory <name, createMethods[]> {

     abstract class <name>AbstractFactory {
          for (createMethod : createMethods) {
               public void create<createMethod>() {}
          }
     }

}

template ConcreteFactory extends AbstractFactory <concreteName, implementations[]> {

     public class <concreteName>Factory {
          for (CreateMethod : CreateMethods, implementation : implementations) {
               public void create<createMethod>() {
                    implementation
               }
          }
     }

}

AbstractFactory <Swing> <Button, CheckBox, RadioButton>;

abstract class SwingAbstractFactory {

     public void createButton() {}
     public void createCheckBox() {}
     public void createRadioButton() {}

}

ConcreteFactory <Window>

// Button
<
...
>

// CheckBox
<
...
>
If I didn't persuade you we need to help Copy-Paste pattern and extend more templating then let's look at even greater extension which looming near. That's template recognizing (contemporary solutions name it rather "parsing"). What we are doing if a clause "send mail to John Doe" pronounced?

1. We recognize the natural language template "subject, predicate, object" (it allows to associate words with grammar forms which can be useful in more complex cases).
2. We recognize template of "send" verb and instantiate grammar parameters like "from", "to", "subject", "body".
3. And executing "send".
template clause <subject, predicate, object> {
     subject predicate object;
}

template 'send mail <subject>:<body> to <to>' extends clause <from, send, mail> {

     public <address book>;  // to be instantiated
     public <sending engine>;  // to be recognized

     <from> = System.getProperty("user.name"); // we use a form <from> for clarity
     <to> = 'look for <to> in <address book>';
     if (<subject> == null || <body> == null) 'compose mail <subject, body>';
     send <from, to, subject, body> with <sending engine>;

}

template 'look for <to> in <address book>' {

     ...

}

template send mail <from, to, subject, body> {

     <address book> = ...; // initializing address book
     <sending engine> = Transport;
     ...

}
In our case if compiler meets construction 'send mail "Hello":"Hello, <to>!" to John Doe' then it tries to compare as many patterns as possible.

1. Pattern 'clause' satisfies this pattern (assuming that subject is "I"). So predicate is 'send' and object is 'mail "Hello":"Hello, <to>!" to John Doe'.
2. Then compiler tries to compare it against different versions of template 'send'. Evidently 'send mail' satisfies. Thus subject, body, and to parameters are instantiated.
3. It remains only to instantiate address book and sending engine for correspondingly to extract address of recipient and to send mail. For this we use other two templates.

That's all. Small but nevertheless necessary feature would allow to make language extensions for Java. If you afraid it could stain already existing language constructs then I want to reassure you this couldn't happen just because they use ''. For example:
for (String recipient : recipients) {
     'send mail to <recipient>';
}
And on the contrary such feature will open new wild, wild possibilities not available for any other languages yet.

MINOR SUGGESTIONS

It's always cleaner to set and get parameters (fields whatsoever) by name. Right you say, that's why, for example, you could fetch data not only by index but also by name (and the last choice is preferrable). On the other hand, object-oriented programming was conceived with the same goal: to abstract data in classes and set fields, then pass an class instance in method instead of setting procedure parameters. Sorry, joking. Seriously, namely this feature is still not healed by lifestyle of nowadays programming approaches. I mean handling method parameters.
myInstance.myMethod(4, "Hello World", a, connection);
What do you think about this call? As a rule three parameter is enough. Right. Personally I don't understand what each of them means. Ok. That's the point, named parameters was long awaited in C++ but as Bjarne Stroustrup wrote in "The Design and Evolution of C++" this was declined because of such innovation gives nothing new, would lead to incompatibility with old code, and will contribute to the bad style of programming. Personally I consider these a little biased objections as a display of conservatism, fear of changes, and human pride (I hope one day I will be forgiven for this revelation). At the same time I agree with these objections but the whole poing of named paramets is missed. The core of Stroustrup's argumentation is the better programming style is the less parameters in calls occured.

Ok, but what's about user-friendly applications with tons of settings, some of them could be added or removed? Well, but you can pass to method an array of objects or an istance of class say MySettings.
myInstance.myMethod(new Object[] {4, "Hello World", a, connection});
or
myInstance.myMethod(new MySettings(4, "Hello World", a, connection));
or
MySettings settings = new MySettings();
settings.setParameter1(4);
...
myInstance.myMethod(settings);
That's fine but let's look on the other hand, what's about user-friendiness of the code itself? Let's consider the above mentioned code. If you are not the developer of myMethod or if you wrote this method aeons ago it would be difficult to understand meaning of parameters. And moreover, in the case even slight changing of parameter count you need to recompile the class of settings.

Let's look on overloading. What's the great sense in writing several methods?
void myMethod(File file); // fetch settings from file
void myMethod(String params); // parsing from the String
void myMethod(int param1, String param2, int param3, Connection conn);
void myMethod(int param1, String param2); // assuming param3 == -1 and conn == null
Overloading is the plaing substitution of the following code:
void myMethod(File file, String params, int param1, String param2, int param3, Connection conn) {
     if (file != null) {
          ...
     } else if (params != null) {
          ...
     } else  {
          if (param3 == -1 && conn == null) {
               ...
          } else {
               ...
          }
     }
}
Well, overloading delivers slightly more cleaner code. By the way, for the case of the last two methods C++ has the feature of default values of method parameters. This could lessen interfaces of some Java classes by 3-5 redefinition of the same methods. But if we deal with entirely different parameters (like in the case of reading file, parsing or plain passing it in the method) then we have to suggest having introduced named parameters we won't avoid if-elses. This concerns implementation but interface could become more clear. This is one of the points of named parameters: we have possibility do not change interface if some feature will be added or removed.
myMethod(file = xmlFile);
myMethod(toBeParsedString = s);
myMethod(param1 = 4, param2 = "Hello World");
In the fact, similar problems can be handled by several solutions:
1. Named parameters (and default values of method parameters).
2. Defaults value of method parameters.
3. Instant initializing of inherent hashmaps like arrays. Something like this:
map = new Object[String] { parameter1 = 4, parameter2 = "Hello World", parameter3 = a, conn = null };.
Basically it would be great even to inroduce only the last two solutions but there a small at this time but biased to expand its influence usage of named parameters. It's again natural language. Parameter names are greatly underestimated as for their names. As I joked object-oriented programming appeared only to pack long list of procedure parameters in class what is partly true. And when the list is very long parameters turned into class fields and are handled as metadata or as part of RTTI information. But what's about other parameters? They have names too and these names no less meaningful than field names. And this is the main reason for named parameters or at least for handling parameter names as information.

CONCLUSION

Definitely Java needs list and map contexts. For example, list context already used if you want to pass multiple arguments as one list or get multiple variables from method. The power of Java is array instantiation just in place.
results = my.myMethod(new Object[] {4, "Hello World"});
for (Object result : results) {
     ... // takes each parameter
}
I think that would be small add-on if maps have the same traits.
results = my.myMethods(new Object[String] {param1 = 4, param2 = "Hello World"});
for (String key : results.keys) {
     Object result = results[key];
     ...
}
Or maybe:
for (String key : Object result : results) { // as specific form for maps
     ...
}
We can even to define our template for such maps.
template '<map> = new <keytype>[<valuetype>] {<<keys = values>[]>}' {

     map = new HashMap(); // we use the simplest form of maps
     for (int i = 0; i < keys.length; i++) {
          if (keys[i] instanceof keytype && values[i] instanceof valuetype)
               map.put(keys, values[i]);
     }

}

Evidently, templating wants to be extended some day. If Java itself wants to remain here in following, say, 50-100 years we have to extend it that way. Here comes the time for programming languages to meet natural languages. And this couldn't happen without introducing template recognizing (or language extensions), isn't?
  • 1. Re: Saying A means saying B
    843853 Newbie
    Currently Being Moderated
    I think the 1.5 people would be the first to say 'generics are not templates'.
    Of course, when you look at generics and autoboxing it becomes a little muddier :-)

    The history of Templates is interesting. I used to read old Dr Dobb's Journals and C/C++ user's journals (don't know what if anything those magazines are called now).

    Just about half of every edition was taken up with subtle little issues with Templates. I mean, thats pretty scary, that half of every issue would be devoted to bugs with a particular language feature. Nasty.

    Of course, way back then every compiler did Templates slightly differently, which compounded the problem.

    So I pretty much formed the opinion that Templates were ugly, evil, 'a bad thing(tm)', and not to be trusted. I haven't seen anything in the last ten years or so to disabuse me of that notion. (Of course the absence of proof is not proof of absence, especially if you're not looking!)

    Nowdays there seems to have emerged something quite different. The C++ camp seems to have split into two, those who program in a C with OO style (eg similar to Java), and those who program by manipulating Templates. The latter sounds to me rather like as if the C++ language had somehow been magically transformed into a functional programming language.

    I don't think Java should try to follow in C++'s footsteps in that regard. Java's key competitive advantage is that is is quite expressive (Interfaces beat the carp out of C++'s multiple inheritance for instance), while remaining simple and easy to write readable/writable code.

    WORA (write once run anywhere) is actually a bad marketing term, because that pretty much describes C. A well written C program can be written once, and then compiled (with minimal if any changes) for most platforms (of course if it relies heavily on an external API such as Win32 that massively restricts its portability). Java on the other hand, is CORA, compile once, run anywhere.

    CORA is of course better than WORA, but its not really that big an advantage. Sun really should focus on keeping Java a lean mean fighting machine of a language, with the emphasis on human readability rather than mere terseness.

    Of course Java doesn't really have anything 'new', its more like an aglomeration of all the good things that other languages had in the 80s and 90s. So it would be natural to look around for other 'good ideas' and incorporate them into the language, right? Well, we just have to be really careful that those things are in fact good ideas, and not just fashions.

    The key to what is good and what is fashion, is that fashions tend to save programmers keystrokes.
    Whereas those things which are good are those that help programmers read, maintain and debug the code. I'll happily give up a saving of 10% of my typing, for a 10% time saving on debugging (other people's code, our code works perfectly first time of course ;-) or a 1% saving on maintenance.

    That is what will make Java last 50-100 years.
  • 2. Re: Saying A means saying B
    843853 Newbie
    Currently Being Moderated
    Rickcarson's comment is so great that I want to re-quote it here:
    We just have to be really careful that those things
    are in fact good ideas, and not just fashions.

    The key to what is good and what is fashion, is that
    fashions tend to save programmers keystrokes.
    Whereas those things which are good are those that
    help programmers read, maintain and debug the code.
    I'll happily give up a saving of 10% of my typing,
    for a 10% time saving on debugging (other people's
    code, our code works perfectly first time of course
    ;-) or a 1% saving on maintenance.
    Besides, I think "good ideas" extends a programmer's
    dictionary of vocabularies, as well as their book of
    programming philosophy.