knowledge-database (beta)

Current group: comp.object

Re: Static vs dynamic

Re: Static vs dynamic  
igouy at yahoo.com
 Re: Static vs dynamic  
Robert C. Martin
 Re: Static vs dynamic  
The Ghost In The Machine
From:igouy at yahoo.com
Subject:Re: Static vs dynamic
Date:13 Jan 2005 13:42:01 -0800
I am profoundly ignorant of C++ which may explain my confusion with
this example.

afaict we don't need an abstract class and concrete class, or virtual
functions, for there to be a problem:

class B {
public:
void f(){};
};

int main() {
B* b = new B();
void* vp = b;
vp.f();
}

test.cpp(10) : error C2228: left of '.f' must have class/struct/union
type
From:Robert C. Martin
Subject:Re: Static vs dynamic
Date:Sun, 16 Jan 2005 08:33:46 -0600
On 13 Jan 2005 13:42:01 -0800, igouy@yahoo.com wrote:

>I am profoundly ignorant of C++ which may explain my confusion with
>this example.
>
>afaict we don't need an abstract class and concrete class, or virtual
>functions, for there to be a problem:
>
>class B {
>public:
>void f(){};
>};
>
>int main() {
>B* b = new B();
>void* vp = b;
>vp->f(); // I corrected this from vp.f(). My fault.
>}

Quite correct. You don't need the abstracts and virtuals. The point
can be made without them.

In the above, the line "vp->f()" is attempting to call the 'f' method
through a typeless pointer. In c++ you aren't allowed to do that. In
C++ every call to a method is checked. The compiler makes sure that
the *type* of the pointer has the appropriate method declared.

For example, had we said: "b->f();", the compiler would have been
quite happy. The pointer 'b' is of type "pointer to B", and B has an
'f' method declared in it.

A dynamically typed language, on the other hand, does not do this
checking at compile time. It would happily compile the "vp-f();"
line. At run time, when this statement was executed, the object
pointed to by vp would be sent a message of the form "execute f". If
the object had a method named 'f', it would execute it. If not, it
would throw an exception.





-----
Robert C. Martin (Uncle Bob) | email: unclebob@objectmentor.com
Object Mentor Inc. | blog: www.butunclebob.com
The Agile Transition Experts | web: www.objectmentor.com
800-338-6716


"The aim of science is not to open the door to infinite wisdom,
but to set a limit to infinite error."
-- Bertolt Brecht, Life of Galileo
From:The Ghost In The Machine
Subject:Re: Static vs dynamic
Date:Fri, 14 Jan 2005 00:01:49 GMT
In comp.lang.java.advocacy, igouy@yahoo.com

wrote
on 13 Jan 2005 13:42:01 -0800
<1105652521.667667.163960@z14g2000cwz.googlegroups.com>:
> I am profoundly ignorant of C++ which may explain my confusion with
> this example.
>
> afaict we don't need an abstract class and concrete class, or virtual
> functions, for there to be a problem:
>
> class B {
> public:
> void f(){};
> };
>
> int main() {
> B* b = new B();
> void* vp = b;
> vp.f();
> }
>
> test.cpp(10) : error C2228: left of '.f' must have class/struct/union
> type
>

void * pointers have no type information at all (beyond them being
a pointer to something). This is true in both C and C++, though
in C pointers have no methods to call anyway. (A fair number
of old C programs used 'char *' as a synonym for 'void *'.)

You are also trying to apply a method to a *pointer*, rather
than what it points to. The correct code is more along the
lines of

B * b = new B();
b->f();

or

(*b).f();

since f is part of B, not of B*. In this usage,
b is a pointer to a class, struct, or union.

There is the method pointer construct

typedef void (B::*mptrType)(void);

with attendant usages

mptrType mptr = &B::f; /* unlike C, the & is required */

(b->*mptr)();
((*b).*mptr)();

but the construct is seldom used. This is *not* to be
confused with the *function* pointer construct

void f() { ... }
typedef void (*fptr)(void);

fptrType fptr = &f;
(*fptr)();

C++ shows a bit of weirdness, as the construct

fptr();

is also allowed. I can't say offhand whether the usage

class B { public: static void f() { ... } };

fptr = &B::f; /* or B::f? */

is allowed or not.

C++ also allows "smart pointers". These are simply classes
which overload three methods:

class APointer
{
public:
operator [const] AThing *() [const] { ... }
[const] AThing * operator ->() [const] { ... }
[const] AThing & operator *() [const] { ... }
};

(I use [const] here to indicate that one can either have a
'const' declaration here, or not, as one's needs indicate.)

These can also be templated, with the usual caveats:

template
class APointer { ... };

Smart pointers are a useful tool although they cannot guard
against certain mistakes such as "losing the loop" memory
leak or the more basic null/bad pointer exception. They
might help against certain initialization problems, but
are strictly optional.

Java, for its part, has no construct for method pointers or
smart pointers, but doesn't really need either because of
introspection and garbage collection.

Briefly put, if one declares a class such as

public class B
{
public B() { ... }
public void f() { ... }
public int g(int x) { ... }
}

in Java, one can do things like

B b = new B();
Class b_c = B.class;
java.lang.reflect.Method m_f = b_c.getMethod("f", new Class[]{});
m_f.invoke(b, new Object[]{});
java.lang.reflect.Method m_g =
b_c.getMethod("g", new Class[]{Integer.TYPE});
Integer r = (Integer) m_g.invoke(b, new Object[]{new Integer(1)});

where permissions allow. Note that Integer.TYPE !=
Integer.class; the former indicates the primitive type
"int", the latter the class for the Integer Object.
The same holds true for Boolean, Byte, Character, Double,
Float, and Long. (String is an Object and has no primitive
type as such. Void.class is probably only seen as a return
value of Method.getReturnType(); there's no real point in
instantiating it.)

Also, method.invoke() must return an Object, not a
primitive, and accept an array of Objects[], hence the
explicit boxing and unboxing in the call above. Java 5
might fix this, allowing for

Integer r = (Integer) m_g.invoke(b, new Object[]{1});

or maybe even

int r = (int) m_g.invoke(b, new Object[]{1});

but I don't have a copy thereof to test it.

As you can probably see, the Java method is clumsier to
actually use, but far more flexible, as one can use *any*
Object and *any* method signature, not merely a subclass
of the given pointer's basetype and the given method
signature.

I don't know C#'s syntax in this area, and C# has the
additional capability of declaring of setter and getter
methods, allowing for some interesting syntactic shorthand
but is also AFAICT a debugging headache.

--
#191, ewill3@earthlink.net
It's still legal to go .sigless.
   

Copyright © 2006 knowledge-database   -   All rights reserved