Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

Type of object?

Name: Anonymous 2010-04-01 11:15

Sup /prog/riders?

I have a common problem (I guess).
I have an abstract class "X" and two classes ("A" and "B") that inherit from it. Also I really need a list that can handle both of them.

List<X> mylist;
mylist.add(A);
mylist.add(B);

Now I need to pick out all items of type A and do something with them, possibly using methods only available in class A and NOT in X or B. In ENTERPRISE JAVA there is "instanceof" but using that sounds just as hacky as saving a type in every object.


Is there a CLEAN way of determining if the object from the X-list is of type A?
Not Java-specific, rather OOP in general.

Name: Anonymous 2010-04-01 11:25

No, this is very much Java-specific.

Name: Anonymous 2010-04-01 11:26

>>2
No.
It's the exact same problem in C++ and D.

Name: Anonymous 2010-04-01 11:36

struct A {
    char type;
    /* ... */
}

struct B {
    char type;
    /* ... */
}

Name: Anonymous 2010-04-01 11:38

>>4
I'm trying not to use this. As soon as I add another class I'll have to update an enum or something that's not in a direct connection to X, A or B.

Name: Anonymous 2010-04-01 11:39

>>1
Is there a CLEAN way of determining if the object from the X-list is of type A?
Yeah, it's called instanceof.  Are you retarded or something?

Name: Anonymous 2010-04-01 11:49

>>6
Wild up/downcasting is never clean. Are you retarded or something?

Name: Anonymous 2010-04-01 11:53

>>2
>>4
>>6
Thanks for nothing. I figured it out myself.
In X create a function that A and B will inherit, then in A and B override the function.
Or make X an interface.
Or see if the language supports declared (but yet undefined) methods in an abstract class.

Name: Anonymous 2010-04-01 11:55

>>8
Congratulations, you just implemented >>4 inefficiently.

Name: Anonymous 2010-04-01 11:57

>>9
Inefficiently, but clean. As if OOP was about efficiency anyway.
If you want efficiency, use C.

Name: Anonymous 2010-04-01 12:00

>>10
char type=xx in every class or void gettype() { return ... }?

Name: Anonymous 2010-04-01 12:01

>>9
That's not inefficient at all, it's still just one function-call. The upside is that any loop over the list doesn't have to make a gazillion checks for every class that inherited from X but just calls the function and lets the object decide what to do with it.

Goddamnit /prog/, is here anyone who can actually program?

(in before assembler > *)

Name: Anonymous 2010-04-01 12:02

>>11
more like

abstract class X { int x; void move() {x += 1}}

class A : X {}
class B  : X {void move(/* LOLNO */)}

Name: Anonymous 2010-04-01 12:14

>>12
... What?

Name: trackpads are shit 2010-04-01 12:19

>>12,14
Anyway. It doesn't matter it's doing a gazillion of, it'll still do a gazillion. In your case it will now do a gazillion function calls. In the other way, X's function will switch for whichever type it encounters.

Anyway, why are you being a shit? We tried to help (you know what /prog/ are like), we gave you some perfectly valid answers, you said 'Thanks for nothing' and then proceeded to say "This is why I'm right and you're wrong" even though you were the one asking the question in the first place.

Name: Anonymous 2010-04-01 12:19

>>12
#include <stdio.h>
#include <sys/times.h>

struct _o {
 int type;
 int i;
} o[1024];

int main() {
 int i,j;
 clock_t time_1;
 struct tms time_s;
 for(i=0;i<1024;i++) {
  o[i].type=rand()&1;
  o[i].i=rand();
 }
 time_1 = times(&time_s);
 for(i=0;i<1048576;i++) {
  for(j=0;j<1024;j++) {
   if(o[j].type)
    o[j].i--;
   else
    o[j].i++;
  }
 }
 printf("Took %d ticks\n",times(&time_s)-time_1);
 return 0;
}


Took 420 ticks

#include <stdio.h>
#include <sys/times.h>

struct _o {
 int (*gettype)();
 int i;
} o[1024];

int gettype_a() {
 return 0;
}

int gettype_b() {
 return 1;
}

int main() {
 int i,j;
 clock_t time_1;
 struct tms time_s;
 for(i=0;i<1024;i++) {
  o[i].gettype=rand()&1?gettype_a:gettype_b;
  o[i].i=rand();
 }
 time_1 = times(&time_s);
 for(i=0;i<1048576;i++) {
  for(j=0;j<1024;j++) {
   if(o[j].gettype())
    o[j].i--;
   else
    o[j].i++;
  }
 }
 printf("Took %d ticks\n",times(&time_s)-time_1);
 return 0;
}


Took 670 ticks

Name: Anonymous 2010-04-01 12:25

>>14
class X { char type; }
class A extends X { move(/*...*/) }
class B extends X {  }
/* somewhere else */
for each I in mylist { if I.type == "A" {I.move()} }

VERSUS

>>13
for each I in mylist {I.move()}

The second one is a lot faster because there won't be a check for the type in every iteration. And even if B.move() does exactly nothing it's still faster than running that if or (even worse) 'instanceof' where every single execution will most likely take even longer than 20 iterations through functions that don't do anything.

ALSO:
Now what happens if there's a class C that inherits from X that will have to use move(), too?
The first example will need another implementation of move() and the IF inside the loop will need to get extended. In the second example you don't have to do anything.
That doesn't have anything to do with execution speed, but it's an important factor nonetheless.

Name: Anonymous 2010-04-01 12:29

>>16
Oh, you were talking about pure C.
Nevermind.

Name: Anonymous 2010-04-01 12:35

>>15
We tried to help (you know what /prog/ are like)
No, I do not frequent this board. And you made me remember why. Thanks, I guess.

we gave you some perfectly valid answers
NO, you didn't. I already knew about the two given examples and I EXPLICITLY stated that they are "hacky" (read: "bad"). The problem was that I didn't know the CLEAN way to do it (which I also EXPLICITELY stated).

All I got was dipshits repeating the stuff I posted.

Name: Anonymous 2010-04-01 12:44

>>19
And yet you still skirt around the accusation of being a shit, because you are one!

Name: Anonymous 2010-04-01 12:46

>>20
Of course I am. If people are being shit to me (i.e. >>6) I'm being a shit towards them, too.

Name: Anonymous 2010-04-01 12:53

I don't see how this changes anything.  In Java you still have no access to type-specific object methods or object variables unless you cast it into that object.  I can think of AWTEvent handling as an example.  After I determine if the object is of type Mouse*Event or type KeyEvent, I still have to cast it into one or the other to access the specific of its event report.

Name: Anonymous 2010-04-01 12:54

>>21
That doesn't set up a good tone for the rest of the thread, especially when you are being retarded - what defines ``clean''? Clean to look at, or generated-bytecode-type-clean?
What do you have against instanceof, especially when it's the kind of operator pertinent to your situation?
Why did you bother posting a question, only to come up with a completely unrelated answer not 38 minutes later? You couldn't have expected anyone to follow your train of thought, especially when you give them no clues as to what you do want (you only said what you don't want, and the human mind doesn't work on negatives - whatever you do, don't think of a puppy right now).

Ask a stupid question (or what effectively amounts to no question), get >>2-1000 as an answer.

Name: Anonymous 2010-04-01 12:58

You could just make a virtual method in the abstract class and define it in the 2 derived classes, then just call it to do what you want.


if (o instanceOf A) do_A(A);
else if (o instanceOf B) do_A(B);
else error(...);

//would get translated to:

do(o);

// You would have to define the do method in both A and B's class definition.

Name: Anonymous 2010-04-01 12:58

I have a common problem (I guess).

yes, you use OOP.

i cant believe how nobody posted this yet, shame on you /prog/.

Name: >>24 2010-04-01 13:01

Oops, I meant to say:

if (o instanceOf A) do_A(o);
else if (o instanceOf B) do_B(o);
else error(...);

Name: Anonymous 2010-04-01 13:10

You really only have two options. Either you cast, or you don't cast.

If you cast, you can access type-specific fields and methods, but you have to determine the type: instanceof or a hacky replacement of it.

If you don't cast, you need overloading to do the work for you, so you end up with hacky dummy methods doing nothing for objects of every type except the wanted one.

The only clean solution is to keep a separate list of only type A objects, and that explodes in complexity so it's only clean for a very short while.

Name: Anonymous 2010-04-01 13:11

instanceof
OOP
*facepalm*

Name: Anonymous 2010-04-01 13:14

>>22
you still have no access to type-specific object methods or object variables unless you cast it into that object.

Doesn't really matter in this case. The list is being used for something very general.
If it wasn't, it would have been more clever to have a list for each type seperately.

>>23
what defines ``clean''? Clean to look at, or generated-bytecode-type-clean?
While the meaning of "clean" might be debatable in this case it isn't. Anyone who has a list of X shouldn't care if the current item is of subclass A, B, C ... Objects are supposed to be independent from everything else. If you don't do it that way, you might just not use OOP at all.

What do you have against instanceof, especially when it's the kind of operator pertinent to your situation?

It encourages bad design - other parts of your program will need to know the exact structure and inheritance of classes. Also (as already stated) as soon as you add a third class you'll have to look up every single instanceof-operation and possibly modify it because C happens to need the same method.
If you do it without it, the object C is isolated from the rest of the program. The iteration over the list works just as fine as before and you don't have to change anything.

Why did you bother posting a question, only to come up with a completely unrelated answer not 38 minutes later?
How exactly was that solution unrelated? After some more googling I found out that's common practice.

You couldn't have expected anyone to follow your train of thought, especially when you give them no clues as to what you do want
I wrote I have a list of type X and want to do specific stuff with all As. And I knew before that there was a clean, OOP-way solution to it. I just couldn't remember it.
And because I knew there would be 50 replies of "use instanceof" I made sure that won't get posted.
I SHOULD have posted why I dislike instanceof and the storing of a type, but I figured people on a programming board would know.

Ask a stupid question (or what effectively amounts to no question), get >>2-1000 as an answer.

The question wasn't stupid at all. I just found the solution myself. I figured I'd just share it with you so you may take some profit from it.
Stop being butthurt.

Name: Anonymous 2010-04-01 13:20

>>24
Uh... is there a difference between doing it the way you proposed and overriding it in classes that want to do it differently? You'll have to implement them in any case, right?

Name: Anonymous 2010-04-01 13:28

This thread was a simple inheritance question. How did OP not know what to do straight away?
I have Father, Son and Daughter classes. It is 1862 and I want the Father to School() only his Sons.
Clearly you must make Daughter.School() return FALSE and Son.School() return TRUE, where Father.School() could return anything. How is this not simple through the raw power of OO?

Name: Anonymous 2010-04-01 13:34

>>30
You'll have to write a method for each new class you want to support.

If you're doing it in Java,C# or C++, you'll need a base abstract class of an interface which defines that method.

If you're doing it in Lisp, you can just define a mixin and specialize on that:

(defclass touchable-mixin () ())

(defclass A (touchable-mixin)
  (slot-1 slot-2))

(defclass B (touchable-mixin)
  ())

(defgeneric touch (item)
  (:documentation
   "Touch some item."))

(defmethod touch ((item touchable-mixin)) 
  (format t "You touched an instance of ~A: ~A~&" (class-name (class-of item))
          item))

(defun pick-random (&rest items &aux (length (length items)))
  (nth (random length) items))

(defparameter *bag-of-As-and-Bs*
  (loop repeat 5
        collect (make-instance (pick-random 'A 'B)))
  "A random list of instances of class A or B.")

(mapc #'touch *bag-of-As-and-Bs*)
;Prints:
;You touched an instance of A: #<A {24A1A9F9}>
;You touched an instance of A: #<A {24A1AA49}>
;You touched an instance of B: #<B {24A1AA99}>
;You touched an instance of B: #<B {24A1AAD1}>
;You touched an instance of B: #<B {24A1AB09}>

Name: Anonymous 2010-04-01 13:44

I'd just have a switch(o->type) and add whatever code is needed to it whenever I add a new type of object. Simple and centralized.

Name: Anonymous 2010-04-01 13:47

If one has to typecase, they might as well not use OO.

Name: Anonymous 2010-04-01 13:53

ITT we don't understand OOP

Name: Anonymous 2010-04-01 14:14

>>33
That's exactly what OP didn't want, even though it's safer - if a third class claims to inherit from X, say.

Name: Anonymous 2010-04-01 18:02

I’ll BT a bit.  OP said he 「needed to pick out all items of type A and do something with them, possibly using methods only available in class A」.

With the OP having chosen such a layout for the program, it is already obvious to us that the number of classes is limited and well known, and that the specified actions are highly specific to the procedure OP is implementing.

Adding this as a method to X is nonsense – You would be arbitrarily moving parts of your procedure into a object method, not only creating non-cohesive spaghetti code, but cluttering up X’s API with one-off methods as well.

You have a list with a couple of different classes of objects, and want to treat one of them specially.  Instanceof is clearly the straight-forward, readably and maintainably explicit way of doing so.  It is no less 「clean」 than special casing 5 to be the exit point of a loop, rather than adding an .is_last_value_of_loop_in_main() method to integers.

Don't change these.
Name: Email:
Entire Thread Thread List