Re: object system...
- From: "cr88192" <cr88192@xxxxxxxxxxx>
- Date: Tue, 13 Jan 2009 23:54:00 +1000
"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> wrote in message
news:1obq05ayl19zl$.mghpopxh028w.dlg@xxxxxxxxxxxxx
On Mon, 12 Jan 2009 22:50:28 +1000, cr88192 wrote:
"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> wrote in message
news:au6iq7quarsb$.196jbwbwvvafi.dlg@xxxxxxxxxxxxx
On Mon, 12 Jan 2009 11:49:12 +1000, cr88192 wrote:
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.
Not in a typed system. You cannot have an object in a context where its
type is unknown. If the type is known, no reflection is needed. [ If we
considered upward closures, which allow objects to propagate out of its
type declaration and pulling the latter with it. That in effect would
eliminate the notion of context, and necessarily make type the first-class
object. In short, this way or another, you do not need reflection in this
form.]
we need to know the type to know the type...
in a statically compiled app, all of the type information is known at
compile time, and goes away.
this leaves nothing, however, when more code is created at runtime...
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..
Same as 3, the context must know the type where an operation on it should
happen. Context /= object /= type.
only when the code already exists at compile time...
if the code does not exist, it can't be typed at this point, and so the
information needs to be kept around until it can be used...
at the point the code is generated, THEN we can verify that it has the right
types...
for example, right out of the box does the OS know every possible app that
can run on it?...
no, the OS only knows about apps after they are installed...
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.
That is self-referential and thus inconsistent. To make it consistent such
systems need to be split into two, neither of which is self-referential.
For example, into interpreter and the code to interpret. For the
interpreter the code is data. The types are still static for the code and
do not need to be known there.
not really...
when we compile to machine code, there is no longer an interpreter...
it IS possible for an app to start writing its own machinery without the
need for an interpreter, and without the severe semantics and language break
usually implied by this (the app being split into an "inside" and "outside"
world).
in this case, an interpreter does not build a confined inside world, but a
compiler starts integrating itself with the outside world, thus allowing the
app to perform tasks beyond those originally built into the statically
compiled parts of the app.
in an extreme forms, the app core could be stripped down to a very small
kernel, and then build itself almost purely at runtime (by loading code and
data off disk, ...). granted, I have not had much reason to do this (usually
the staticly compiled code by far outweighs the dynamically compiled code),
but this is not a fundamental requirement in the design.
as it so happens, a lot of the needed information can by mined from headers
and similar...
however, there are some problems that just go beyond what can be statically
compiled...
this is why VMs of one sort or another are inevitable for many apps...
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...
But still outside objects. The point is that without a clear separation of
what belongs where, you will get an inconsistent, very inefficient system.
There is no reason why a Boolean object has to carry type description with
it. It is just one bit, there is no place for additional information.
I don't need the boolean to carry type info with it, or at least not with
the running code.
it is only needed as the code is written, and can go away, the boolean then
becomming a raw integer value (zero or nonzero), just like any other C-style
boolean...
I don't need tagged values or other such things to make it all work...
it all serves a role much like headers serve when compiling C.
their role is primarily informational, not needed for running the code, but
sure as hell needed for building the code...
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...
Object is an instance of its type. It is not an instance of the class
rooted in the type. An instance of the class is the object's type. Other
instances are types derived from it.
this doesn't make sense...
it is declared against a class but it uses the instance.
This is another case. If a polymorphic object is declared, then it is an
instance of the type which is a transitive closure of the class. I don't
know which case you mean, polymorphic or a non-polymorphic one.
I am not sure what is being said here...
it is not declared against the instance, nor is it used against the
class...
When object is not declared to have a type related to the interface, then
any operation of the interface applied to the object is a type error.
In a consistent strong typed system, you just cannot do these things. That
is the idea of strong typing, not to allow this mess.
again, this does not make sense.
do you use an interface to access static methods?...
usually not (nor am I sure this is allowed within languages like Java or
friends, AKA, the instance is needed to make the interface work...).
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...
Right, it makes a lot of sense to leave that to the programmer. The
language shall flag a conflict, and the programmer must resolve it in an
appropriate to hin way. He can say that xi getter/setter pair is to be
overridden in all parents by one pair or else by a set of pairs. There are
lots of combinations, especially when taking into account public/private
views.
yeah...
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.
This is done in Ada, where use of built-in types is strongly discouraged.
That gives you a lot of optimization unavailable in C. Consider a simple
example:
procedure Foo (A : in out Some_Array) is
subtype Index is Integer range A'Range; -- Constrained to the range of A
I : Index := ...;
...
A (I) := 23;
No index range check here is necessary, because the compiler knows that I
may not be outside the index range of A. It is declared to be inside it.
That the implementation would use a 64-bit hardware integer for it does
not
matter.
now, can you demonstrate that this provides a usable performance gain?...
I may put a little more weight into this claim if evidence can be shown, or
at least a justifiably solid explanation is given...
"compiler can choose" does not necessarily mean "faster"...
maybe it means "can omit bounds check", but C does not use these anyways
(and more recent compilers, such as those for C#, are in many cases able to
figure out when to leave out the bounds check).
more so, just because one "thinks" the compiler will use a certain type,
does it mean the compiler will actually do so?... it is sufficient only
that, for what it matters, the behavior is preserved.
on neither x86, nor on x86-64, should this case make much difference.
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).
Which makes C programs non-portable. We are developing
platform-independent
networking middleware for hard real time (dozens of µs). Surely we do not
do it in C. Ada does not have preprocessor, yet we compile the same code
on
different platforms *without* modifications.
usually, for most things (general-purpose software development), only a few
archs matter:
x86, x86-64, and PPC...
some esoteric code may need ARM, but for probably most developers, these are
not in the target domain anyways (embedded developers are their own
island...).
anyways, FWIW, conventions usually are established for particular
architectures, for example, 'int' is 32 bits on 32-bit x86, x86-64, and PPC.
why should we really care then about real-mode, ARM, m68k, ... ?...
and, surely, the people who develop for these archs, well then can deal with
the issues with the arch they have decided to target.
more so, if an app works on Windows, Linux, and Mac, then generally it is
considered as supporting "everything" (or, at least, "everything that
matters"...).
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.
It depends on the type of. If you lack this information in types you
cannot
write a program with defined semantic.
In Ada I write:
type T is range 1..2;
this instructs the compiler to implement a semantics that makes impossible
to assign 2+2 to a variable of the type T.
yes, but typically the compiler usually does not need to know this.
all that is needed to know is that the types are big enough to hold the
values in question, and if there is an overflow, that is the programmers'
problem (or, possibly, the fault of whoever it was trying to compile the
code on whatever arch it does not work on...).
they can fix the problem, but who ever says it is expected or required to
work?...
it is like when driving a car... a simple fault can crash the car and/or
kill people, and it is a matter requiring a decent level of skill and
attention, and lacking much to prevent all this, yet if the driver crashes
the car, that is their problem, not the problem of anyone else...
but, anyways, if needed, there are exact sized integers:
int16_t; int32_t; int64_t; ...
more so, for many tasks, how can one justify using a language like Ada
anyways?...
it is not C, C++, Java, or C#, ... and that, in itself, is a major
detractor...
beyond any merits of the language, there are the merits and costs of the
established situation, where this is not one of the languages commonly used
for coding, thus leading by default to interoperability problems with the
more established technologies...
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
.
- Follow-Ups:
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- References:
- object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- Re: object system...
- From: cr88192
- Re: object system...
- From: Dmitry A. Kazakov
- object system...
- Prev by Date: A hopefully interesting design question ...
- Next by Date: Re: object system...
- Previous by thread: Re: object system...
- Next by thread: Re: object system...
- Index(es):
Relevant Pages
|