For Programmers: Free Programming Magazines  


Home > Archive > Java Help > August 2005 > Re: Im getting frustrated and angry!









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Re: Im getting frustrated and angry!
Dale King

2005-08-18, 6:00 pm

I think we are drifting off-topic here. I listed a number of features
that explain the differences between Java's compilation model and C's
compilation model. I was not arguing for a particular model, just
explaing how they differ with respect to how to build the software.

You seem to want to argue the merits of those features.

Tor Iver Wilhelmsen wrote:
> Dale King <DaleWKing@insightbb.nospam.com> writes:
>
>
> But that's because if foo.c and bar.c reference each other's fields or
> methods, the C compiler will happily delay resolving them.


All it delays is locating them physically in memory. All information
about the type, size, etc. are "resolved" at compile time. And Java also
delays resolving them. It delays it until runtime.

Once again the reason is that the C compiler only uses source files for
input, never object files. Since the object files are not used for input
there is no circularity.

I am not saying the difference is good or bad, just that it exists and
is why make is incompatible with Java and why Java is a more difficult
build problem requiring more sophisticated tools (which ly seem to
only exist in IDE's like Eclipse)

> Java has namespace concerns that C lacks. Everything belongs
> somewhere, not in some global scope.


And I fail to see any relevance to that.

>
> Per compilation unit. But that's because unlike Java, that object is
> not a namespace - except for the case of static variables. And the C
> compiler can do it because it does not have a "package" concept.


Once again irrelevant. Java could have been designed to produce one
class file per compilation unit. First it would have enforced only
defining one top-level class per compilation unit just as enforces it
for public classes. If you added to that having nested classes actually
be part of the top-level class file then you would have achieved one
class per compilation unit and not weakend the "package" concept one bit.

>
> Again you are ignoring the quite important linking step. Everything
> _isn't_ in textual source code at that point; everything is in object
> files.


And once again the issue was circularity not text vs. binary. I only
talked about the compilation step because that is all that is need to
explain that the models are different because one model is circular and
the other is not.

In the C compilation model there is no circularity. Object files depend
only on C source and header files. Libraries and executables depend only
on object files.

In Java there is circularity because a class file is dependent on a
source file and other class files. Those other class files can depend on
this class file, thus a circularity.

Once again my point was not that one compilation model is better than
the other, merely that they are different and make is incompatible with
Java's model. The circularity means that it is a more difficult problem.

>
> Sort of correct: It would eventually end up as object files, but they
> could have another intermediate dependency-aware format before that.
> (Digital had a generic three-address code output you could get from
> their MIPS Ultrix C compiler for instance.)
>
> Java .class files (or C# executables) are also an "intermediate" step
> before Hotspot/JIT turns it into native code at runtime.


And in that case they would have gained circularity and had a more
difficult build problem.

>
> Yes, but that holds for every virtual machine language, from p-code
> and WAM via Perl and Python to Java and the .Net CIL.


Which only shows my point that they are different and why they are
different.

>
> Well, it seems to be more a case of separating "interface" (the
> symbols available to the compiler) and "implementation" (the actual
> locations available to the linker).


That interface would include type information as well, but in that it is
no different from Java. There is no implementation information from
class B that Java uses when compiling class A. It is only using its
"interface" information. C splits that physically in source files but
that is only a convenience.

>
> Again: It has everything to do with it. The difference is that the
> "linker" is not involved in
> cc -c a.c
> but it is involved in
> javac a.java


No, the linker in Java has not been eliminated in Java by moving it into
the compiler it is moved to runtime. The output of the C compiler are
files that contain the implementation for the code in this source file
and it contains strings describing what it needs from other object
files. Java classes are just the same. The class file contains the
implementation for this class and for accessing other classes it has
strings saying what variables and methods are needed from other class
files. The resolution of those references is done in the link step for
C, but in Java it is done in the JVM at runtime.

>
> I think the issue here is that Ant's Java compilation task is supposed
> to "build everything you need". So it may be inefficient but as long
> as the build file actually include all source files in its file set,
> it should be as correct as any make file that include all .o files
> needed, and has one of your beloved .o.c rules. :)


But the issue is that Ant's javac task does *NOT* build everything you
need. Here is an example using only 2 source files for these 2 classes:

public class Main
{
public static void main( String[] args )
{
Foo.test();
}
}

public class Foo
{
public static void test()
{
System.out.println( "Foo.test()" );
}
}

Here is a simple build script to test it:

<project name="JavacTest" default="compile" basedir=".">
<target name="compile">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="." destdir="." />
</target>
</project>

Compile it and everything works OK. Now edit Foo.java and make the test
method take a parameter, but don't edit Main.java.

Run Ant again. It says "BUILD SUCCESSFUL", but the code crashes with an
exception. Ant did not recompile Main.java.

If we used the depends task it would have deleted Main.class to force a
recompilation. That is if you knew to use the depends task since it
isn't mentioned prominently anywhere. And there are still cases that
depends does not catch. And doesn't it seem like a real hack at this point.

>
> You mean you cannot add a .class.java rule because Foo.class is not
> always in Foo.java. What you fail to realize is that Foo.class is used
> in Java in a different way than foo.o is used in C compilation: It not
> only holds the code, but "Foo" is also a compilation symbol in its own
> right. You avoid this problem in C because the "foo" in "foo.o" isn't
> used for anything and only needs to be unique for filename reasons.


No, I mean what I said. You seemed to have Ant and make in my sentence.
It is not possible to write an Ant script to compile Java code that
guarantees correctness and efficiency. It is of course impossible to
write a makefile that does it for Java, but it is possible to write one
that does it for C/C++ compilation.

But this is not a discussion of make vs. Ant. What I am trying to
discuss is what are the requirements of a good build tool.

Make meets the requirements for C/C++ development. Neither Ant nor make
meet those requirements for Java development. There are tools that do
meet those requirements for Java development, but none that I know of
for command line building.

So my point is let's get a command line tool that does it right instead
of lying about Ant saying it is "make done right".

>
> Of course there is:
>
> <project default="hi">
> <target name="hi">
> <echo>Hello world!</target>
> </target>
> </project>
>
> Yes, it's not very useful, but your statement was very literal.


And my statement also had context which you took it out of.

>
> Yes, but that has a huge caveat about "certain assumptions about the
> makefile rules" that can just as well be applied to build.xml rules.
>
> ..o.c:
> $(CC) $(CFLAGS) -c $*.c -o $*.obj
>
> This target states it produces foo.o from foo.c, but the actual code
> produces foo.obj. Can make detect that the required target was not
> built and report the error?


No, but that does not invalidate the result from the paper. The paper
says that if your make rules obey have the characteristics described in
the paper then your make will be safe. Your rule violates those
characteristics so does not guarantee a safe make. I fail to see the
relevance of the fact that you can write bad makefiles.

>
> What you do in Ant's javac task is to build everything you need. It
> may be less efficient that Make's dependency analysis, but frankly the
> dependency analysis plus repeated batch-file-like invocation of the
> compiler per compilation unit does not sound that efficient either.


Do you still think it builds everything you need after my previous
example? The way I summarize the result from that paper is to say if you
ever have to do a "clean" to get a correct build then your build tool
(or your build script) is broken. In the case of Ant the build tool is
broken.

> Except that somefile.h can include otherfile.h and vice versa. Hence
> the need for the #ifndefs or Objective-C's #import to "escape" an
> endless loop in the preprocessor. But you are correct there are no
> circular dependencies between the .o files.


Good, we agree. My only point was to explain how they are different.

>
> Producing intermediate code. In many ways .class files are also
> intermediate code, with the jar/war being akin to the linked product
> (executable) in C compilation. But, again, .o files are not part of
> the symbol set in compilation, .class files are.


No, the jar is like a static library. A static library is just an
archive containing object files. Linking in Java is done at runtime. C
only does linking at runtime for shared libraries.

>
> At least less of it, since dependencies are postponed to link time,
> when - quelle surprise - you list all the object files:
>
> cc a.o b.o c.o -o program
>
> If a.o uses a symbol from b.o and I instead try
>
> cc a.o -o program
>
> the linker will complain that there is an unboud symbol.


As will Java when it does its linking at runtime.

> How can you not see this is not far removed from listing more than one
> ..java file when using javac?
>
> javac -d build A.java B.java C.java
> jar cf program.jar -C build *


Because it *is* very far removed.

>
> No, it's a different build problem to C, and hence a tool crafted for
> separate compiler/linker steps (C, Fortran etc.) is not suitable for
> it.


Once again, Java has separate compiler linker steps, its just that
Java's is done at runtime.

>
> No, because the output artifacts are part of the symbol set.


You basically said that Java can't have C's compilation model because it
has its own model. That is circular reasoning. There is nothing about
the language that requires Java's model.

> They are
> needed because Java does not have header files to predeclare
> namespaces and symbols for the compiler.


The compiler could read the java file and parse it to get the
information about the class instead of reading the class file. I'm not
arguing that it should have, just that it could have and then would have
a similar compilation model to C.

>
> Which tasks? Which of the standard Ant tasks, except for javac, do any
> dependency checking at all?


There are some. Those that don't are inefficient because they always
perform the action (just like a batch file). Those that

>
> No, it's a collection of tasks, some of which may represent commands.
> Make uses commands like a batch file.


A task is just a named collection of commands.

>
> No, because targets can be excluded using if/unless.


The ordering is still fixed.

>
> Yes, so the dependency graph is more complex.


The difference is that make has a dependency graph while Ant just
executes statements in sequence. I know you can define dependencies
between tasks, but that just controls ordering.

>
> You mean it reevaluates all rules after each target? How is that
> "efficient"?


It can decide it doesn't need to do things while Ant just does the next
statement in the sequence whether it needs done or not.

>
> The decisions are akin to
>
> <available property="has-Foo.class" file="Foo.class" />
> <target name="build-Foo.class" unless="has-Foo.java" />
> <javac file="Foo.java" ... />
> </target>
>
> except automated with implicit wildcards.


No, but I have to cut this short and get to work.


--
Dale King
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com