Débat Objective-C 2.0

135

Réponses

  • schlumschlum Membre
    10:40 modifié #62
    dans 1229065802:

    Quand à  "thoughts of Cameleon", on ne voit pas le code sur lequel il compare ObjC et C++. Tout cela ne me semble pas très scientifique, et dans ce genre d'études de cas particuliers, tout et son contraire peut être dit. 



    First I wrote a mini benchmark -- get a very basic object (a couple of ivars, one method "plop" assigning a value to an ivar), and then create an instance, initialize it (call the init method), call the one method the object has, then deallocate the object. 10000000 times.


    Il manque quoi pour savoir ligne pour ligne le code (aux noms de variables près) ?  :P
  • psychoh13psychoh13 Mothership Developer Membre
    10:40 modifié #63
    dans 1229077362:

    dans 1229072496:

    Et je ne suis toujours pas d'accord sur le fait qu'ObjC n'est fait que pour les interfaces, le système de messages n'est pas fait pour les traitements lourds, ça oui, mais tous les traitements moins lourds où ObjC n'est pas un problème s'étendent au-delà  de la simple interface... Sinon, quel intérêt d'avoir séparé Foundation et AppKit.

    Oui le mot "interface" que j'ai utilisé est réducteur. La ligne de partage est évidemment moins nette, et elle évolue dans le sens favorable à  Objective-C : c'est ce que tu m'avais fait comprendre dans un post précédent.

    dans 1229072496:

    Ce code n'est plus utilisable dans ObjC 2.

    J'ai réussi à  le faire fonctionner (?)

    <br />#import &lt;Foundation/Foundation.h&gt;<br /><br /><br />#define STACKCLASS(class) typedef struct { @defs(class) } &#092;<br />__CLASS_ON_STACK__##class;<br /><br /><br />#define STACKOBJECTISA(objectName,className,classIsa) &#092;<br />__CLASS_ON_STACK__##className __INSTANCE_ON_STACK__##objectName; &#092;<br />__INSTANCE_ON_STACK__##objectName.isa = classIsa; &#092;<br />className* objectName = (className*)&amp; __INSTANCE_ON_STACK__##objectName;<br /><br /><br />#define STACKOBJECT(objectName,className) &#092;<br />STACKOBJECTISA(objectName,className,[className class]);<br /><br />@interface Test :NSObject {<br />}<br />@end<br />@implementation Test<br />-(void) plop {<br />}<br />@end<br /><br /><br />STACKCLASS(Test);<br />int main(void) {<br />	int i;<br />	for (i=0; i&lt; 10000000; i++)<br />	{<br />		STACKOBJECT(test,Test);<br />		[test init];<br />		[test plop];<br />	}<br />	return 0;<br />}<br />
    



    Ce code marche... En 32 bits ; en 64, le compilateur va t'emmerder, il va te dire que @defs n'est plus utilisable dans le nouvel ABI, mais c'est le seul problème, après tu peux toujours utiliser des structures intelligentes, mais tu dois définir la structure manuellement, ce qui peut être emmerdant...

    Mais oui, tu peux envoyer des messages à  n'importe quoi, il suffit juste qu'il y ait dans les premiers octets un pointeur sur un objet Class, et tu peux à  partir de là , coller n'importe quoi.

    Par exemple, un tableau de char :
    #import &lt;Foundation/Foundation.h&gt;<br /><br />@interface Test :NSObject<br />@property int v;<br />@end<br /><br />@implementation Test<br />@synthesize v;<br />@end<br /><br />int main(void)<br />{<br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, sizeof(Test));<br />&nbsp; &nbsp; char fakeObject[sizeof(Test)] = {0};<br />&nbsp; &nbsp; ((id)fakeObject)-&gt;isa = [Test class];<br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [(id)fakeObject v]);<br />&nbsp; &nbsp; [(id)fakeObject setV:5];<br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [(id)fakeObject v]);<br />&nbsp; &nbsp; return 0;<br />}
    

    ;)
  • schlumschlum Membre
    10:40 modifié #64
    En Objective-C on peut quand même faire des trucs bien crades  ;D
    Et après on dénigre le C++  :P
  • Philippe49Philippe49 Membre
    10:40 modifié #65
    dans 1229078422:

    Il manque quoi pour savoir ligne pour ligne le code (aux noms de variables près) ?  :P

    Le code et les options de compilation


    #include <stdio.h>
    #define GIGA 1000000000
    int main(void) {
    int i,a=5,b=2,aux;
    for(i=0;i<GIGA;i++)
    {
    aux=b;b=a;a=aux;
    }
    }
    % gcc pgm.c -o pgm -Os
    % time pgm

    real 0m0.513s
    user 0m0.507s
    sys 0m0.004s

    ===================================

    #include <stdio.h>
    #define GIGA 1000000000
    int main(void) {
    int i,a=5,b=2,aux;
    for(i=0;i<GIGA;i++)
    {
    aux=b;b=a;a=aux;
    }
    printf("%d\n",a);
    }

    % gcc pgm.c -o pgm -Os
    % time pgm
    5

    real 0m1.529s
    user 0m1.508s
    sys 0m0.009s
    %

  • Philippe49Philippe49 Membre
    10:40 modifié #66
    dans 1229079691:

    Mais oui, tu peux envoyer des messages à  n'importe quoi, il suffit juste qu'il y ait dans les premiers octets un pointeur sur un objet Class, et tu peux à  partir de là , coller n'importe quoi.

    C'est exactement un exemple de ce que je veux dire pour "faire du C dans de l'Objective-C",
    mais mes mots sont peut-être mal choisis ...
    On peut avec l'Objective-C jouer sur les deux tableaux (et pas seulement sur deux tableaux) et c'est ce qui me plait dans Obj-C

    Plus généralement, c'est l'idée de pouvoir rentrer dans le fonctionnement à  n'importe quel niveau, à  n'importe quelle profondeur, sans avoir besoin de changer de langage.
  • psychoh13psychoh13 Mothership Developer Membre
    10:40 modifié #67
    Donc moi je propose comme implémentation des objets ObjC sur la pile, ceci :
    #import &lt;Foundation/Foundation.h&gt;<br /><br />#define $(className, name) char __stacker__##name [sizeof(className)] = {0}; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; className *name = (id)__stacker__##name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ((id)name)-&gt;isa = [className class]<br /><br />@interface Test :NSObject<br />@property int v;<br />@end<br /><br />@implementation Test<br />@synthesize v;<br />@end<br /><br />int main(void)<br />{<br />&nbsp; &nbsp; $(Test, fakeObject);<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [fakeObject v]);<br />&nbsp; &nbsp; [fakeObject setV:5];<br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [fakeObject v]);<br />	return 0;<br />}
    


    Vous n'aurez aucun warning, et ça marchera sans problème, vous pourrez appeler des méthodes sans cast sans déréférencement, par contre évitez bien sûr les retain, release, et malheureusement vous ne pouvez pas non plus retourner l'objet...

    Mais voici le code qui vous permettra d'utiliser, de façon crade bien sûr, les objets alloués sur la pile en Objective-C comme n'importe quel objet C++ :

    #import &lt;Foundation/Foundation.h&gt;<br /><br />#define $$(className)&nbsp; &nbsp; &nbsp; struct __stacker__##className<br />#define $$$$(className)&nbsp; &nbsp; struct $$(className) { char __hidden__[sizeof(className)]; }<br /><br />#define $$$(name)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; __stacker__##name<br /><br />#define $(className, name) className *name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  struct __stacker__##className $$$(name) = {{0}}; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  name = (id)&amp; $$$(name),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  ((id)name)-&gt;isa = [className class]<br /><br />@interface Test :NSObject<br />@property int v;<br />@end<br /><br />@implementation Test<br />@synthesize v;<br />- (id)init<br />{<br />&nbsp; &nbsp; if((self = super.init))<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; self.v = 10;<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return self;<br />}<br />@end<br />$$$$(Test);<br /><br />$$(Test) stackObjectReturn(void);<br /><br />int main(void)<br />{<br />&nbsp; &nbsp; $(Test, fake);<br />&nbsp; &nbsp; $$$(fake) = stackObjectReturn();<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [fake v]);<br />&nbsp; &nbsp; [fake setV:5];<br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [fake v]);<br />	return 0;<br />}<br /><br />$$(Test) stackObjectReturn(void)<br />{<br />&nbsp; &nbsp; $(Test, fakeObject);<br />&nbsp; &nbsp; [fakeObject init];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return $$$(fakeObject);<br />}
    


    Alors, quelques explications :
    • $$(nom de la classe) : vous donne le type sur la pile de l'objet.
    • $$$(nom de l'objet) : vous donne le nom de l'objet sur la pile, c'est celui qu'il faut retourner.
    • $$$$(nom de la classe) : crée le type de la pile, il faut donc le faire juste après la création de la classe pour fonctionner.
    • $(nom de la classe, nom de l'objet) : crée la variable sur la pile, vous ne pouvez pas envoyer de message directement à  cette déclaration, et "nom de l'objet" sera le receveur des messages.


    J'ai presque honte d'avoir écrit ce code. :D Cependant, ça prouve que la création des objets sur le tas uniquement est un choix, plus qu'une réelle contrainte... Sachant que beaucoup de classes de Cocoa ne peuvent pas fonctionner comme ça.

    PS : Le nombre de $ correspond à  l'ordre dans lequel j'ai imaginé les macros. ;D
  • schlumschlum Membre
    10:40 modifié #68
    test.m :
    #import &lt;Foundation/Foundation.h&gt;<br /><br />@interface Toto : NSObject<br />{<br />	int a,b;<br />}<br /><br />- (void)plop:(int)i;<br /><br />@end<br /><br />@implementation Toto<br /><br />- (id)init<br />{<br />	if((self=[super init])!=nil)<br />		a = b = 0;<br />	return self;<br />}<br /><br />- (void)plop:(int)i<br />{<br />	a = i;<br />}<br /><br />@end<br /><br />int main()<br />{<br />	unsigned long i,end = (unsigned long)1000*1000*10;<br />	for(i=0;i&lt;end;++i) {<br />		Toto *t = [[Toto alloc] init];<br />		[t plop:1];<br />		[t release];<br />	}<br />	return 0;<br />}
    


    Test.cpp :
    class Toto {<br />private:<br />	int a,b;<br />public:<br />	Toto() : a(0),b(0) { };<br />	virtual ~Toto() { };<br />	inline void plop(int i) { a = i; };<br />};<br /><br />int main()<br />{<br />	unsigned long end = (unsigned long)1000*1000*10;<br />	for(unsigned long i=0;i&lt;end;++i) {<br />		Toto t;<br />		t.plop(1);<br />	}<br />	return 0;<br />}
    


    Compilation :
    g++ -O0 -W -Wall -o testCpp test.cpp
    gcc -O0 -W -Wall -framework Foundation -o testObjc test.m

    Exécution :
    % time ./testObjc<br />./testObjc&nbsp; 3,80s user 0,01s system 64% cpu 5,905 total
    

    % time ./testCpp<br />./testCpp&nbsp; 0,24s user 0,00s system 72% cpu 0,335 total
    


    J'ai les mêmes résultats que lui... facteur 16.

    Quand on fait ce genre de benchs, on n'active pas l'optimisation, sinon on a des résultats faux.
    Si j'active les optimisations -O3, j'ai un facteur de 728...  ::) (le compilo C++ apparemment vire le code inutile, donc c'est immédiat ; par contre, l'optimisation c'est pas le fort du compilo Obj-C apparemment...)
  • schlumschlum Membre
    10:40 modifié #69
    Et si je fais "on the heap" en C++ :
    Toto *t = new Toto;<br />		t-&gt;plop(1);<br />		delete t;
    


    J'obtiens encore le même résultat que lui :
    ./testCpp &nbsp;1,16s user 0,00s system 64% cpu 1,806 total
    


    facteur 3
  • psychoh13psychoh13 Mothership Developer Membre
    décembre 2008 modifié #70
    Voici l'implémentation finale de la création d'objets Objective-C sur la pile.
    Cette implémentation permet aux objets de recevoir les messages retain, release, retainCount, copy et mutableCopy.
    De plus, il est possible de transformer l'objet sur la pile en objet sur le tas avec la méthode __unstack.

    Le code final fait 27 lignes. ;D

    #import &lt;Foundation/Foundation.h&gt;<br /><br />#define $$(className)&nbsp; &nbsp; &nbsp; struct __stacker__##className<br />#define $$$$(className)&nbsp; &nbsp; $$(className) { char __hidden__[sizeof(className)]; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@interface __stacker_class__##className : className {}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@end&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@implementation __stacker_class__##className&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (oneway void)release { NSLog(@&quot;Can&#39;t release a stack object&quot;); }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (id)retain { return self; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (id)autorelease { return self; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (NSUInteger)retainCount { return UINT_MAX; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (className *)__unstack {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;className *ret = [className alloc];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;memcpy(((id)ret) + 1, ((id)self) + 1, sizeof(className) - sizeof(Class)); &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return ret;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (id)copyWithZone:(NSZone *)zone { return self; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (id)mutableCopyWithZone:(NSZone *)zone { return self; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@end&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@interface className (__stacker__)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (className *)__unstack;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@end&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@implementation className (__stacker__)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- (className *)__unstack { return self; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@end<br /><br />#define $$$(name)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; __stacker__##name<br /><br />#define $(className, name) className *name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct __stacker__##className $$$(name) = {{0}}; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;name = (id)&amp; $$$(name),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#092;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;((id)name)-&gt;isa = [__stacker_class__##className class]<br /><br />@interface Test : NSObject { int v; }<br />- (int)v;<br />- (void)setV:(int)value;<br />@end<br /><br />@implementation Test<br />- (int)v { return v; }<br />- (void)setV:(int)value { v = value; }<br />- (id)init<br />{<br />&nbsp; &nbsp; if((self = [super init]))<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; [self setV:10];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return self;<br />}<br />@end<br />$$$$(Test)<br /><br />$$(Test) stackObjectReturn(void);<br /><br />int main(void)<br />{<br />&nbsp; &nbsp; $(Test, fake);<br />&nbsp; &nbsp; $$$(fake) = stackObjectReturn();<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [fake v]);<br />&nbsp; &nbsp; [fake setV:5];<br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [fake v]);<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; id obj = [fake __unstack];<br />&nbsp; &nbsp; NSLog(@&quot;%d&quot;, [obj retainCount]);<br />&nbsp; &nbsp; [obj release];<br />&nbsp; &nbsp; <br />	return 0;<br />}<br /><br />$$(Test) stackObjectReturn(void)<br />{<br />&nbsp; &nbsp; $(Test, fakeObject);<br />&nbsp; &nbsp; [fakeObject init];<br />&nbsp; &nbsp; [fakeObject release]; // Can&#39;t release stack object<br />&nbsp; &nbsp; return $$$(fakeObject);<br />}
    


    Maintenant il ne reste plus qu'à  l'implémenter dans le compilateur... :D
  • schlumschlum Membre
    10:40 modifié #71
    ça ne pose pas de problème avec les class clusters ?
  • psychoh13psychoh13 Mothership Developer Membre
    10:40 modifié #72
    Avec les classes clusters, ça ne marchera clairement pas, puisque la classe publique d'un class-cluster est abstraite, et ne définit aucune variable d'instance... Il faudrait avoir accès aux tailles des sous classe concernée dès la compilation, ce qui n'est pas possible puisqu'on n'a pas leur interface...
  • NseaProtectorNseaProtector Membre
    10:40 modifié #73
    dans 1229080678:

    dans 1229078422:

    Il manque quoi pour savoir ligne pour ligne le code (aux noms de variables près) ?  :P

    Le code et les options de compilation


    #include <stdio.h>
    #define GIGA 1000000000
    int main(void) {
    int i,a=5,b=2,aux;
    for(i=0;i<GIGA;i++)
    {
    aux=b;b=a;a=aux;
    }
    }
    % gcc pgm.c -o pgm -Os
    % time pgm

    real 0m0.513s
    user 0m0.507s
    sys 0m0.004s

    ===================================

    #include <stdio.h>
    #define GIGA 1000000000
    int main(void) {
    int i,a=5,b=2,aux;
    for(i=0;i<GIGA;i++)
    {
    aux=b;b=a;a=aux;
    }
    printf("%d\n",a);
    }

    % gcc pgm.c -o pgm -Os
    % time pgm
    5

    real 0m1.529s
    user 0m1.508s
    sys 0m0.009s
    %



    Je ne sais pas comment vous faite pour avoir les temps d'exécution ? j'imagine l'option time pgm, mais comment vous faites ? Vous passez par un fichier make, non ? Sinon en plaçant des  NSLOG en début et fin de code (obj-c et xcode) pour voir sur mon macbook je remarque un facteur de 5 en compilant avec LLVM et en activant quelques options... C'était juste pour dire...
  • Philippe49Philippe49 Membre
    10:40 modifié #74
    dans 1229154750:

    Je ne sais pas comment vous faite pour avoir les temps d'exécution ? j'imagine l'option time pgm, mais comment vous faites ? Vous passez par un fichier make, non ?

    Pas besoin de make, d'ailleurs je n'ai jamais eu besoin d'utiliser make sous mac, XCode le fait à  notre place.
    time ./pgm lance l'exécution de ./pgm sous l'exécutable time, ce dernier se chargeant de mesurer les durées attribuées au système et au programme.
  • Philippe49Philippe49 Membre
    décembre 2008 modifié #75
    dans 1229083740:

    Et si je fais "on the heap" en C++ :
    Toto *t = new Toto;<br />		t-&gt;plop(1);<br />		delete t;
    


    J'obtiens encore le même résultat que lui :
    ./testCpp  1,16s user 0,00s system 64% cpu 1,806 total
    


    facteur 3



    Cet exemple est extrêmement sensible ...
    Mais quelle interprétation donner aux essais suivants et à  ceux de Schlum : est-ce une question de pile/tas , ou d'optimisation cachée, ou de quantité de mémoire utilisable nécessitant des déblocages successifs selon le compilateur et l'environnement, ...

    Voici un essai en C
    <br />#include &lt;stdio.h&gt;<br />#include &lt;stdint.h&gt;<br />typedef struct machin {<br />	int64_t x;<br />	int32_t y;<br />} machin;	<br /><br />static inline int plop(int x) { return x+1;}<br /><br />int main(void) {<br />	unsigned long i,end = (unsigned long)1000*1000*10;<br />	for(i=0;i&lt;end;i++) <br />	{<br />		machin t={0,12};<br />		t.x=plop(t.x);<br />	}<br />}
    


    % gcc pgm3.c -o pgm
    % time pgm

    real 0m0.085s
    user 0m0.083s
    sys 0m0.002s
    %

    3 fois moins que C++

    ou cette autre version :

    #include &lt;stdio.h&gt;<br />#include &lt;stdint.h&gt;<br /><br />typedef int (*FONCTION)(int ) ;<br /><br />int plop(int x) { return x+1;}<br /><br />typedef struct machin {<br />	int64_t x;<br />	char s[28];<br />	FONCTION f;<br />} machin;	<br /><br />int main(void) {<br />	unsigned long i,end =(unsigned long)1000*1000*10;<br />	for(i=0;i&lt;end;i++) <br />	{<br />		machin t={.x=0,.f=plop};<br />		t.x=t.f(t.x);<br />	}<br /><br />}<br />
    


    % gcc pgm.c -o pgm
    % time pgm
    real 0m0.379s
    user 0m0.360s
    sys 0m0.003s


    % gcc pgm.c -o pgm -O3
    % time pgm
    real 0m0.009s
    user 0m0.007s  # l'optimisation détruit le contenu de la boucle
    sys 0m0.002s



  • NseaProtectorNseaProtector Membre
    10:40 modifié #76
    Quel exécutable time ? Je ne le vois ni dans les menus xcode, ni dans les applications developer ni dans les utilitaires ???
  • Philippe49Philippe49 Membre
    décembre 2008 modifié #77
    Deux autres exemples en dynamique :
    #include &lt;stdio.h&gt;<br />#include &lt;stdint.h&gt;<br />#include &lt;stdlib.h&gt;<br />typedef struct machin {<br />	int64_t x;<br />	int32_t y;<br />} machin;	<br /><br />static inline int plop(int x) { return x+1;}<br /><br />int main(void) {<br />	unsigned long i,end = (unsigned long)1000*1000*10;<br />	for(i=0;i&lt;end;i++) <br />	{<br />		machin * t=malloc(sizeof(machin));<br />		t-&gt;x=0;<br />		t-&gt;x=plop(t-&gt;x);<br />		free(t);<br />	}<br />}<br />
    


    % gcc pgm3.c -o pgm
    % time pgm
    real 0m1.021s
    user 0m1.012s
    sys 0m0.005s
    %

    et à  la méthode anti-belge  // sans free(t)
    % gcc pgm3.c -o pgm
    % time pgm
    real 0m1.060s
    user 0m0.878s
    sys 0m0.175s





  • Philippe49Philippe49 Membre
    10:40 modifié #78
    dans 1229157874:

    Quel exécutable time ? Je ne le vois ni dans les menus xcode, ni dans les applications developer ni dans les utilitaires ???



    Tu ouvres le terminal (dans /Applications/Utilitaires)
    Tu y tapes cd ~/Desktop
    Pour vérification, tapes ls tu dois y voir la liste des fichiers sur ton bureau.
    Tu crées un fichier pgm.c (avec TextEdit ou XCode) que tu enregistres sur le bureau
    Puis tu tapes les instructions de ce post.

    time est un fichier binaire exécutable qui doit se trouver dans /usr/bin/ , on peut le voir en tapant dans le terminal ls /usr/bin/t*
  • schlumschlum Membre
    10:40 modifié #79
    Pour le -O3, l'optimisation a dû virer le code...
    Pour le reste, tu travailles avec des structures et des pointeurs de fonctions ; c'est pas vraiment comparable (même si les objets sont des structures spéciales...)
  • NseaProtectorNseaProtector Membre
    décembre 2008 modifié #80
    dans 1229158331:

    dans 1229157874:

    Quel exécutable time ? Je ne le vois ni dans les menus xcode, ni dans les applications developer ni dans les utilitaires ???





    Tu ouvres le terminal (dans /Applications/Utilitaires)
    Tu y tapes cd ~/Desktop
    Pour vérification, tapes ls tu dois y voir la liste des fichiers sur ton bureau.
    Tu crées un fichier pgm.c (avec TextEdit ou XCode) que tu enregistres sur le bureau
    Puis tu tapes les instructions de ce post.

    time est un fichier binaire exécutable qui doit se trouver dans /usr/bin/ , on peut le voir en tapant dans le terminal ls /usr/bin/t*


    Ok j'ai enfin compris, et surtout j'ai encore appris quelque chose ... MERCI
  • Philippe49Philippe49 Membre
    10:40 modifié #81
    dans 1229159116:

    Pour le -O3, l'optimisation a dû virer le code...

    Les compilateurs doivent bien faire certaines optimisations standards, sinon comment comprendre les différences entre tous ces essais ?

    dans 1229159116:

    Pour le reste, tu travailles avec des structures et des pointeurs de fonctions ; c'est pas vraiment comparable (même si les objets sont des structures spéciales...)

    Je sais assez peu de choses en ce domaine, mais tu vois autre chose dans un objet qu'une telle structure C avec quelques pointeurs en plus pour régler les problèmes liées au fonctionnement spécifique (héritages, ...) ? Le compilateur C++ n'est pas fait en C ?
  • Philippe49Philippe49 Membre
    10:40 modifié #82
    Dans la série mon compilateur est un grand sensible


    Sans aucune boucle
    #include &lt;stdio.h&gt;<br />#include &lt;stdint.h&gt;<br />typedef struct machin {<br />	int64_t x;<br />	int32_t y;<br />} machin;	<br /><br />int main(void) {<br />	unsigned long i,end =(unsigned long)1000*1000*10;<br />//	for(i=0;i&lt;end;i++) <br />//	{<br />////		machin t={0,12};<br />////		t.x++;<br />//	}<br />}
    

    % gcc pgm34.c -o pgm -O3
    % time pgm

    real 0m0.003s
    user 0m0.001s
    sys 0m0.002s
    %

    Avec une boucle vide
    #include &lt;stdio.h&gt;<br />#include &lt;stdint.h&gt;<br />typedef struct machin {<br />	int64_t x;<br />	int32_t y;<br />} machin;	<br /><br />int main(void) {<br />	unsigned long i,end =(unsigned long)1000*1000*10;<br />	for(i=0;i&lt;end;i++) <br />	{<br />////		machin t={0,12};<br />////		t.x++;<br />	}<br />}
    


    % gcc pgm34.c -o pgm -O3
    % time pgm

    real 0m0.010s
    user 0m0.007s
    sys 0m0.002s
    %


  • psychoh13psychoh13 Mothership Developer Membre
    10:40 modifié #83
    Pour savoir où se trouve un exécutable il suffit de faire which <nom de l'exécutable> :
    $ which time<br />/usr/bin/time
    
  • schlumschlum Membre
    10:40 modifié #84
    Je ne vois pas pourquoi faire rentrer en jeu des pseudo optimisations du compilateur (à  part quand on compile avec -O3 et qu'il vire tout le code inutile)... Tous ces exemples sont logiques  ???
  • schlumschlum Membre
    10:40 modifié #85
    Et encore une fois ça ne sert à  rien de faire des bench avec -O3 ; tu ne sais pas ce qu'il bidouille derrière... Il enlève ou raccourcit le code qu'il a calculé comme inutile etc.
    :P
  • Philippe49Philippe49 Membre
    décembre 2008 modifié #86
    dans 1229161855:

    Et encore une fois ça ne sert à  rien de faire des bench avec -O3 ; tu ne sais pas ce qu'il bidouille derrière... Il enlève ou raccourcit le code qu'il a calculé comme inutile etc.
    :P

    Oui mais quelle est la part d'optimisation sans aucune option ?

    dans 1229161419:

    Je ne vois pas pourquoi faire rentrer en jeu des pseudo optimisations du compilateur (à  part quand on compile avec -O3 et qu'il vire tout le code inutile)... Tous ces exemples sont logiques  ???

    Tu trouves logique la multiplication par 7 pour exécuter une boucle vide après optimisation ??  acceptable comme erreur, mais logique ?

    int main(void) {
    unsigned long i,end =(unsigned long)1000*1000*10;
    i=end;
    }

    user 0m0.001s

  • schlumschlum Membre
    10:40 modifié #87
    Ben c'est qu'il n'enlève pas toute la boucle à  priori... Il estime qu'il a besoin des calculs qui sont faits dans le corps du "for()" je suppose.
    Par contre, avec ou sans contenu, ça donne le même temps, donc il enlève le contenu.

    Avec -O0 il n'y a aucune optimisation...
  • NseaProtectorNseaProtector Membre
    décembre 2008 modifié #88
    dans 1229162753:

    Tu trouves logique la multiplication par 7 pour exécuter une boucle vide après optimisation ??  acceptable comme erreur, mais logique ?


    Il faudrait voir le code assembleur pour voir la différence et voir se qu'il fait réellement, branchement court par exemple, le fait de faire tenir en cache la boucle, il pourrait dans un cas faire un branchement et dans l'autre avoir le code à  la suite, il peut dans un cas tenir compte de l'adresse mémoire paire et pas dans l'autre, etc...
    Note: lubrifier les pipelines, peut-être ?
  • MalaMala Membre, Modérateur
    décembre 2008 modifié #89
    Et bein ça y est. Me v'là !  :)

    Après avoir tout lu, je suis relativement d'accord avec Ali sur le fait que qui peu le plus peu le moins au niveau des nouvelles fonctionnalités d'Obj-C. Perso, j'aime bien les properties car elles allègent le code et comme cela a été souligné rien n'empêche de surcharger une méthode si nécessaire. Je trouve juste le @synthesize et l'obligation de déclarer la variable d'instance qui va en face de trop finalement.

    Je suis par contre surpris que le parallèle entre les classes de Cocoa et de Core Foundation n'est pas été plus marqué dans les propos. Notamment, si l'on aborde le sujet sensible de la perte de performance d'Obj-C par rapport à  des langages plus statiques. La plupart des objets de Cocoa peuvent en effet être castés vers leurs homologues de Core Foundation. On se retrouve alors à  manipuler, tableaux, dictionaires, etc directement en C. Pour des boucles assez critiques, cela me semble plus efficace que d'essayer de gagner du temps (ou plutôt d'en perdre moins) en passant par des mises en cache de certains appels.

    Pour les différences de performances entre tas et pile, c'est un problème vieux comme le monde. L'allocation sur le tas a tout de même de grosses contraintes vu le dynamisme des langages objet. Bien sûr, sur une boucle de 3 lignes ça "déchire sa race" mais dans la vraie vie de tous les jours? Je ne connais pas beaucoup de programme en C qui fasse l'usage d'alloca par exemple. Et il me semble que l'usage de pointeurs sur des structures de données permet de limiter très largement les conséquences de la pile puisqu'on peut ainsi taper n'importe où dans la mémoire mais je me trompe peut-être.

    Question optimisations de compilation, je rejoins Schlum. Il ne faut pas espérer de miracle. Les appels de méthodes en Obj-C sont lent point barre. C'est le talon d'Achille de ce langage d'où mon allusions à  Core Foundation pour palier à  cette limite sans devoir réinventer le C.

    En tout cas, c'est une discussion très intéressante comme je les aime sur ce forum.  :P
  • Philippe49Philippe49 Membre
    10:40 modifié #90
    dans 1229265537:

    Je suis par contre surpris que le parallèle entre les classes de Cocoa et de Core Foundation n'est pas été plus marqué dans les propos. Notamment, si l'on aborde le sujet sensible de la perte de performance d'Obj-C par rapport à  des langages plus statiques. La plupart des objets de Cocoa peuvent en effet être castés vers leurs homologues de Core Foundation.
    ...
    C'est le talon d'Achille de ce langage d'où mon allusion à  Core Foundation pour palier à  cette limite sans devoir réinventer le C.


    Pourquoi pas, mais il serait temps que le ménage soit fait entre Carbon, CoreFoundation, CoreGraphics, etc ... et toutes ses librairies C qui se chevauchent, on finit par ne plus savoir quelle ressource prendre pour optimiser son code. Ok pour une belle librairie C à  utiliser sous Objective-C, mais unifiée, et avec une logique documentaire telle qu'on l'apprécie habituellement avec les outils XCode.
    Tiens, ça me rappelle une autre discussion il y a deux ou trois mois où je disais que le remplacement du C de Carbon par Obj-C n'était qu'une question de dénomination des routines C ...  :)
  • psychoh13psychoh13 Mothership Developer Membre
    10:40 modifié #91
    Bah normalement, Carbon devrait sauter tôt ou tard alors...
    Les autres frameworks ont été conçus plus ou moins autour de Cocoa.
Connectez-vous ou Inscrivez-vous pour répondre.