Steve said:
[...]
So, we have a workable solution, using an existing .dll, but I'm
surprised that there isn't a way to include common source code in
multiple programs. In my VB, Java, and Flex programs, I've typically had
modules or libraries for different kinds of tasks (file transfer, USB
communication, database access, etc.) and only included them when needed
for the specific program being developed.
Be sure you are comparing apples-to-apples. Even in C#, you can get away
with compiling into a given module different source files according to
your needs. It's when you do that in multiple modules that all are shared
within a single program that you run into trouble.
Conversely, even in other languages, using compilation as your
code-sharing approach rather than having sharable libraries (static or
dynamic) is at a minimum a poor choice, and in the worst case can lead to
similar problems to what you see in C#. I don't know specifically about
Flex or VB, but for sure in C/C++ and Java you would have similar issues
that you're seeing here (in Java, they are almost identical, because the
type system is stronger, like in .NET).
In some languages – C/C++ for example, and for all I know VB (but _not_
VB.NET) – declared simple types are merely descriptors of memory layout.
You can safely redeclare a given type over and over without any problem.
But in .NET (and Java), types are full-fledged citizens within the
program, requiring each type to be unique within a given program. You
can't declare a type with the same name in two different modules that will
be shared in a single program without some kind of ambiguity resolution,
because the run-time needs to know which implementation of a type to use,
and that implementation has to be consistent across the entire program.
Even in C++, if the type has implementation (i.e. functions, especially
non-inlined ones), then you'll run into duplicate function names and have
the same problem. The linker will resolve the duplicates on a
function-by-function basis rather than for the whole type at once, but
it's still an issue. And worse, if the layout of the type's data members
isn't the same between the two implementations that were included, any
time an instance of the type is created in one place and then used in a
different place using the other implementation, that will be a serious
problem.
And even in languages where you can get away with that sort of thing, it's
not because the language is inherently immune to the issue. At best, it's
because the language is failing to warn you that something dangerous may
be going on.
Having the same type declared in two different source files used in the
same program means that it's possible for the two different declarations
of the type to have different implementations. I would be surprised to
find any system that didn't resolve the ambiguity by picking one
implementation or the other (mixing two implementations could obviously be
catastrophic). But even picking one implementation without warning you
means that you could have a serious bug in your code without even
realizing it, because your code is using a different implementation for a
type than you thought it was.
In your particular example, you are literally including the same source
file. You could safely get away with ignoring the warning, because you
know yourself that the implementations will be identical. But at the
point in time when the linker is pulling the different implementations
together, it has no practical way to know that the implementations are the
same. Even if it tracked the source file, the two assemblies in which the
type is being declared need not have been compiled using the same version
of the given source file, and of course the source file information is in
the PDB file, not the assembly itself, and may not even be present.
So, the compiler warns you. And that's a really good thing. If you are
using other languages that don't warn you about this kind of problem,
you're working without a net. Don't be surprised if at some point you
fall and crack open your head.
Frankly, for me the bottom line is this: if you are sharing code, the
proper way to do it is through compiled libraries, not by recompiling the
same code over and over.
Pete