Re: object system...




"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> wrote in message
news:au6iq7quarsb$.196jbwbwvvafi.dlg@xxxxxxxxxxxxx
On Mon, 12 Jan 2009 11:49:12 +1000, cr88192 wrote:

for example, few are likely to doubt that a 'for' or 'while' loop is
preferable to an 'if-goto' construction, none the less, goto and labels
are
the more general construct, and if-goto can be considered more as
syntactic
sugar.

Yes, and the evolution of languages goes from more general to less
dangerous constructs. It is no problem to get it Turing complete, so
genericity was not an issue since the day one.


yes, many of these things are still kept around for the rare case they are
needed.

like, for example, C# still has pointers and goto if one wants to use them
(although AFAIK C# lacks inline ASM, and for this one has to compile native
code and call into it...).


none the less, it is a lot easier to optimize code with loops or
if-then-else, than code written via gotos (optimizing if a given branch
is
always true or false, unrolling loops, ...), however it is also the case
that nearly every compiler I am aware of converts over to the use of
gotos
fairly early on (and I am not aware of any IL which uses high-level
control
flow rather than labels and gotos/jumps...).

[...]

so, yes, although one can use prototype features, they should not, as the
additional overhead costs are high.

Also, in a typed system you do not need to store any specific type
information at run-time. The type tag is needed in only two cases:

1. The object is polymorphic and its specific type is unknown until
run-time

2. The representation of a non-polymorphic object is same as the
representation of a polymorphic object rooted in the specific type of the
former.

The case 2 is usually deployed by when objects are by-reference.


3. when "reflective" abilities are needed, for example, when writing more
code that can use the object outside its original context.

4. when rebuilding the code. in this case, usually the type information is
kept purely as sideband or scaffolding, and once the code is built it ceases
to matter, or at least until more code needs to be built around it..

....


for example, my C compiler, for x86-64, emits mangled names. now, these
names are mangled to include a full definition of the function arguments and
return type. has the C become dynamically typed?... no, this is because it
allows the linker to figure out how the calls work, and then automatically
write code to glue together several different calling conventions...

is the glue code dynamically typed?... no, once the code is built, it is
statically typed just like most of the other code...

now, granted, this is not the ideal way to deal with this problem, but it is
was a useful solution (helping me get the compiler ported...).


also, note that the memory overhead of storing a class is not exactly
small
either (a class likely by far dwarfs the instance), but this is OK as the
number of classes is likely to be small vs the instances (in total, each
class is likely to take several KiB of memory...)

You do not need to store classes (except when first-class objects) at all.
Classes are truly static when there exist only non-polymorphic objects and
polymorphic objects. But you would need to store classes if you had
classes
of classes, e.g. second order polymorphic objects.


only if the code is statically compiled and need not change...

if things can change, it is all needed, so that the old code fragments can
be flushed and rebuilt, ...


but, yes, if nearly all of the code can see itself as its own data, it can
utilize itself in building new code and features.

(it is sort of like the program whos output is its own source, only a lot
more useful...).

for example, I can trivially note that several parts of my project contain
non-trivial parts which are code written by code, be it parts of my
assembler, linker, or compilers.

we work from abstract listings, say tables and lists in some text file, and
this expands into chunks of code needed for performing a task (say, gluing
my object system to native machine code, generating the tables and logic
code for processing an instruction set, ...).


all this is stuff that, though presumably could be written by hand, it is
tedious to do so.

a function which takes abstract data and converts it into code, and converts
this code into native machine code, and then this code can be integrated
with the running app, and with most of it performing just as well as if it
came out of a static compiler...

these can be powerful tools...


Interface deals with the type, not an object of. As any base type it
adds nothing being a separate type from the result. Inheritance is an
algebraic operation that takes some arguments, like interface, and
produces the
result, the type or interface.

we use interfaces against instances / objects, not against classes...

Yes I see. This is what I certainly do not want to have = object of same
type implementing different interfaces! That looks like schizophrenia.

this is common practice though, and actually one of the major uses of
interfaces. well, that and allowing different classes to be used in the
same
place (AKA: a poor man's duck typing...).

One does not need to be schizophrenic, it is no problem for an object to
have a type to be a member of many classes. The relationship is:

an object <--1:1--> the type <--1:n---> classes of

An object has exactly one type. Interfaces deal with types not objects. An
interface declares some set of operations defined on some set of values.
It
is meaningless to apply this to an individual object. It is like to have 1
integer without 2. How + is supposed to work? Integer interface applies to
all integers.


it applies to an object, which is an instance of a class implementing an
interface...

it is declared against a class but it uses the instance.

it is not declared against the instance, nor is it used against the class...


Here is a picture of tripled doubly-linked web of nodes:

http://www.dmitry-kazakov.de/ada/components.htm#Generic_Doubly_Linked_Web

Each node participates in three lists. In terms of interfaces a node
inherits doubly-linked list interface three times and no merging
happens.

I am not an expert on Ada, but I am not sure I am seeing any
interfaces...
to me, as a guess, it looks more like MI is being used here?...

No, unfortunately Ada cannot this because it also "merges" interfaces as
Java does. The example represents a use case which cannot be handled by
Java-like interfaces. Each element on the figure is in three
doubly-linked
lists. If doubly-liked list would be an interface, the element's
interface
would have to inherit it three times keeping all three separate. That in
turn would cause a name clash. [My solution is irrelevant here, because
it
is not interface/inheritance based.]

To summarize:

interface = abstract type - implementations
abstract type = type - instances

If you have abstract type, you do not need interfaces, they already do
all
what you need (provided MI).

The limitation not to have implementations (characterizing interfaces)
is
just silly. It does not save you from the conflicts upon composition of
interfaces. There are two competing models of composition:

1. Idempotent: A + A = A
2. Additive: A + A /= A

*Both* models have their use cases. Both models require certain actions
to
undertake upon composition of same interfaces independently on whether
implementations are present or not.

then why were you saying that interfaces do not merge?...

Because they do not. I need three different operations Next, when element
is in three lists.


ok.

in effect, they do merge, and this is why one can't implement the same
interface multiple times, because in effect this neither works, nor does
it
make sense conceptually.

?

MI could probably do this, in the funky way MI tends to work, but tends
to
disallow merging the inheritence graph (I had thought this tendency to
fragment was an implementation artifact, but apparently it has some
use...).

Why MI should tend to disallow anything? In C++ we can find both cases 1
and 2 supported. Where is a problem?


class A {
int xi;
....
}

class B1: A {
....
}

class B2: A {
....
}

class C: B1, B2 {
....
}

what of xi in C?...

C *c;

we have c->B1::xi and c->B2::xi, which may potentially have different
state...

if these are separate, then the variable is fragmented, and I originally
thought this was a fault or artifact. now, I realize that this has a few
potential uses...


usually the typesystem provides a similar typeset to those which exist
on
the CPU, and to do different would reduce performance.

Nope, that is C stance. The idea of a higher-level language is to
abstract
the machine, not to expose it.

?...
then why don't we all go and use Haskell or Prolog?...

I don't see any connection. There might be problems with Haskell and
Prolog. Anyway it is not a language popularity contest. As we all know the
language of all times is Visual Basic...


not really...

in many language rankings the top 3 tend to be C, C++, and Java...

VB tends to be a little lower on the list, and seems to be declining.


Haskell and Prolog are very abstract, and it is difficult to find much of
that ugly hardware left...
nevermind that the languages are both almost unusable and largely useless
for doing anything practical...



I say, the purpose of a higher level language is to get more work done
more
effectively, and if this is by hiding or exposing the machine is not
important, only that more work be done, that it be done faster, and that
it
be done better...

It cannot be unimportant, because exposing machine prevents some vital
optimizations. For example, if you handle register allocation manually,
you
prevent the compiler to do it for you. And with most of optimizations the
compiler will beat you by margin.

That is apart from the issues of code reuse, portability, safety,
maintainability etc.


maybe so, but if there were useful optimizations that could be done here,
almost invariably it would have been done.


anyways, it is also the case that in many language specifications, such as
the C standard, it never really says what exact size the types are anyways,
only that they are "at least this big" (little else being said about
representation).

it is only de-facto convention, then, for example, that int is 32 bits...
it could be 16, 32, 64, or 128, or even 24, 48, or 96, the standard does not
say...

more so, many newer compilers represent smaller types, such as char and
short, in many cases as 32 bit integers (they are extended on load and
truncated when stored). so, really, the compiler does choose the most
effective representation.

on some archs, int is internally represented as a 64 bit value, or
potentially even larger (well, there is at least one arch around which uses
128 bit pointers...).


When you expose machine types, you cannot describe their semantics in a
machine-independent way, obviously.

doesn't matter when the machines in question implement more-or-less the
same
semantics...

How do you define "more or less same semantics?" Computing is discrete,
1+1
is either 2 or else wrong. Does 15326+35221 overflow?


you know... 2+2=5...

whether or not numbers overflow depends on their sizes and other factor.


That gives you no advantages, whatsoever. If modular 2**32 number fits
the
machine register, the compiler would use that far better than me. It is
merely an optimization issue.

maybe, but there is probably some reason that user-variable number types
went away.
COBOL gave us them, and a few languages since, however the common
consensus
would seem to be that they don't offer enough advantage to be worth
including them...

Really? Sorry, but I am dealing with data acquisition and control. It is
damn important to me not to sent 10 E+37 km/h to the wind fan. The thingy
is hundreds of thousands dollars...


formatting need not be based on internal representation...


the great problem is that, at compile time, niether the programmer nor
the code may know all of what may happen at runtime, and not all tasks
are
possible purely through the use of plain logic code, so the result is
that one ends up with a good amount of dynamic facilities, such that
the
programmer can write code (usually, statically), which causes the app
to
begin writing its own code at runtime to accomplish the tasks with
which
it is presented...

Yes, and the language problem is to encircle and insulate this dynamics.
The notion of class (dynamic polymorphism) is such a way.

a class can wrap stuff like this, but so can a plain API.

Really, how? If "plain API" reads "functions and procedures." Then what
are
the types of the arguments and results? void *, I guess?


'void *' is common, but sometimes I use opaque incomplete struct types
(makes the compiler complain more if mixed up).

othertimes, the API itself looks rather normal, it is only its internals
which are weird...


well, this is along with me now splitting my GC and typesystem+object
system
into separate libraries...

Yes.


I went and did so this morning...

might add support for precise GC to my GC (currently, it uses conservative
GC...).

or such...


--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


.



Relevant Pages

  • Re: Grundsatzfrage zum Klassen-Design
    ... Dass, wenn sich Tabellen ändern, sowohl Du als auch ich in den Code ... Sicherlich haben Interfaces ihren Zweck. ... den Compiler zum Generieren von Fehlermeldungen zu bewegen. ... weil mich SPs nun endgültig auf eine DBE festnageln. ...
    (microsoft.public.de.german.entwickler.dotnet.csharp)
  • Re: Apple IIGS ROM 1 or ROM 3, which is better?
    ... of the *simple* indirection cost can be amortized, but compiler ... and every methodology has a terrible dark side. ... code with firm interfaces allowing isolation and factorization. ... the most demanding design activities. ...
    (comp.sys.apple2)
  • Re: Grundsatzfrage zum Klassen-Design
    ... VB6-Zeiten unter Interfaces. ... >> darüberhinaus Deine Klasse MyEmailManager! ... > nicht alle Stellen enstsprechend der Änderung anpasst. ... Sie sind nicht durch den Compiler zu finden. ...
    (microsoft.public.de.german.entwickler.dotnet.csharp)
  • Re: Check a radio button
    ... building systems, which is that you have to keep the compiled code consistent with the ... Key here is that you are thinking that you can enhance interfaces without rebuilding the ... of bugs would simply be due to compiler changes. ...
    (microsoft.public.vc.mfc)
  • Re: Interfaces
    ... Have I specified the interfaces in the most simple manner possible. ... same file, the compiler *might*, repeat might be able to pass some ... but the language is designed to not assume that. ...
    (comp.lang.fortran)