Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Le langage D est-il le successeur du C++ ?

Le , par Florian Goo

0PARTAGES

0  0 
Salut les C++iens,

Suite au séisme provoqué par le retrait des concepts, je lis çà et là des prédictions nostradamussiennes (pacorabanniennes ?) de la mort du C++.
Bon, je ne sais pas si on peut avancer de telles choses aujourd'hui et je n'ai pas non plus spécialement envie que le C++ meure aussi vite (en fait, ce n'est même pas le sujet de la conversation que je souhaite engager), mais j'aimerais malgré tout sortir la tête de mon trou pour voir ce qui se trame au pays de la succession du C++.

Le C++, héritant du C, commence à être un langage assez vieux et par conséquent de plus en plus difficile à réformer. Difficile en effet d'ajouter des killer-features s'intégrant harmonieusement à la version précédente tout en assurant la rétrocompatibilité. Et je ne parle même pas des boulets qu'on se traine depuis le C (le typage faible, le préprocesseur archaïque et j'en passe).

De plus, les alternatives montantes telles que le Java et le C# ne me convainquent pas des masses : faciliter la tâche du développeur d'accord (et encore, je me sens plus libre en C++), mais pas au détriment des performances, ni au cout de l'introduction d'une machine virtuelle ou autre interpréteur dont on connait les inconvénient. Mais bref, ce n'est pas le sujet non plus.

Je viens de me renseigner un petit peu ce matin sur le langage D. Celui-ci se présente comme un re-engineering du C++, ou une remise à plat si vous préférez.
Le D, la puissance du C++ sans sa complexité : vous y croyez ? J'ai pu lire qu'Andrei Alexandrescu (célèbre expert C++), lui, semble y croire.

Je ne vais pas vous faire une présentation des fonctionnalités de D (la page correspondante de Wikipédia le fera mieux que moi), mais celles-ci semble prometteuses.

En tout cas, tout ceci semble assez intéressant, je vais me pencher sur le sujet.

Que pensez-vous de D comme digne successeur de C++ ?
Y a-t-il une alternative plus convaincante selon vous ?

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de ponce
Membre averti https://www.developpez.com
Le 03/02/2010 à 12:48
Oui, il faudrait une discussion "les propriétés encouragent elles les mauvais comportements ?" ou "Pour ou contre les accesseurs, la bataille finale".
2  0 
Avatar de Florian Goo
Membre éclairé https://www.developpez.com
Le 25/07/2009 à 14:34
On a pourtant ce qu'il faut en interface graphique : Qt, gtkmm, wxWidgets et j'en passe…
Quel est le problème ?
1  0 
Avatar de Arzar
Membre émérite https://www.developpez.com
Le 28/07/2009 à 14:11
Citation Envoyé par loufoque Voir le message
Mais de quoi tu parles ?
Du même exemple qu'a donné Florian, je suppose.

Ceci :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//overload for list nodes
template<ListNode SyntaxNodeT>
SyntaxNodeT
convert_node(const tree_node_t& node)
{
return convert_list_node(node);
}

//overload for optional nodes
template<OptionalNode SyntaxNodeT>
SyntaxNodeT
convert_node(const tree_node_t& node)
{
return convert_optional_node(node);
}
au lieu de :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//overload for list nodes
template<class SyntaxNodeT>
SyntaxNodeT
convert_node
(
const tree_node_t& node,
typename boost::enable_if<syntax_nodes::utility::is_list_node>::type* = 0
)
{
return convert_list_node(node);
}

//overload for optional nodes
template<class SyntaxNodeT>
SyntaxNodeT
convert_node
(
const tree_node_t& node,
typename boost::enable_if<syntax_nodes::utility::is_optional_node>::type* = 0
)
{
return convert_optional_node(node);
}

/*
* Utility types
*/
typedef char yes_type;

struct no_type
{
char padding[8];
};



/*
* list_node type trait
*/
namespace list_node_check
{
template<class T>
static
yes_type
check_sig(typename T::item*);

template<class T>
static
no_type
check_sig(...);
}

template<class T>
struct is_list_node
{
static const bool value = sizeof(list_node_check::check_sig(0)) == sizeof(yes_type);
};



/*
* optional_node type trait
*/
template<class T>
struct is_optional_node
{
static const bool value = false;
};

template<class T>
struct is_optional_node<syntax_nodes::optional_node>
{
static const bool value = true;
};
Citation Envoyé par loufoque Voir le message
Leur enlèvement ne change rien en pratique car leurs fonctionnalités s'émulent sans problème avec une syntaxe comparable (je dirais même plus claire et concise).
Très drole.

Et pourtant, bizarrement, dans pas mal d'entreprise, la politique c'est PAS DE TEMPLATE, car justement personne n'arrive à comprendre et maintenir ce genre de "syntaxe comparable claire et concise" à base de boue illisible de SFINAE, traits et autres hacks.
1  0 
Avatar de koala01
Expert éminent sénior https://www.developpez.com
Le 29/07/2009 à 12:13
Salut,

Pour en revenir au noeud du problème, je peux t'assurer que les "chroniques d'une mort annoncées" d'un langages ont eu lieu de tous temps...

Et, de tous temps, elles se sont révélées n'être que des mirages, quel que soit le langage (utilisé de manière professionnelle) visé ou le temps laissé pour qu'elles se réalisent...

Le bémol que l'on peut émettre, c'est que certains langages se sont retrouvé limités à des secteurs de niches particuliers, mais, dans l'ensemble, dés que tu as des développements étalés sur dix ans avec un langage précis, il est souvent plus facile et moins onéreux de trouver "la perle rare" qui connait le langage et de continuer à l'utiliser que reprendre le développement intégral dans un autre langage

Cela a été le cas avec Ada, Cobol, et C quand un nouveau langage a été annoncé (je me demande même si, concernant fortran, il n'y aurait pas eu prophétie identique à la sortie de C), et, pourtant, ils sont toujours utilisés

De plus, la décision prise concernant les concepts en C++ ressemble plus à un ajournement concernant leur mise au point qu'à un abandon définitif

Sans compter le fait que ce n'est pas parce qu'une feature particulière n'est pas adoptée que, forcément, cela implique que le langage subira une "perte de vitesse", même si cette feature semble importante

Tout cela pour te dire qu'il "n'est pas impossible" que l'absence des concepts fasse que certains nouveaux programmeur décident de ne pas l'utiliser, mais qu'il y a encore de la marge pour en arriver au fait que cette absence décide ceux qui l'utilisent à changer de langage

Ceci dit, mon avis personnel est qu'il est bon d'être "spécialisé" dans un langage particulier, mais que cela n'empêche absolument de connaitre au minimum les bases des autres, et qu'il est même souhaitable d'être en mesure de se débrouiller avec

Il n'est pas souhaitable de vouloir les maitriser parfaitement tous, car à trop vouloir savoir tout faire, on en vient à ne rien savoir faire correctement, mais c'est malgré tout une bonne chose que d'être en mesure de poser un oeil attentif sur un code écrit dans un autre langage que celui dans lequel on est "spécialisé" et d'arriver à comprendre ce qui est fait
1  0 
Avatar de JolyLoic
Rédacteur/Modérateur https://www.developpez.com
Le 01/12/2009 à 10:03
Citation Envoyé par Florian Goo Voir le message
Depuis le moment où j'ai appris l'existence des principes « préférez la composition à l'héritage » et « une classe hérite pour être réutilisée dans un contexte polymorphe et non pour réutiliser les fonctions de la classe mère » , je n'ai pas rencontré de cas où l'héritage multiple s'imposait (sauf pour les bidouilles du style boost::noncopyable ou boost::enable_shared_from_this, qui n'auraient pas lieu d'être en D).
Je développe pas mal en c#, qui a les mêmes restrictions que java (ou D ,donc) à ce sujet. Et le manque d'héritage multiple me gêne régulièrement, m'obligeant à dupliquer du code. Dans la plupart des cas, une solution à héritage simple serait possible, mais il faudrait pour ça modifier une classe intermédiaire à laquelle je n'ai pas accès. Est-ce que j'utilise des classes intermédiaires d'une bibliothèque mal conçue ? Je ne le pense pas particulièrement. Et en tout cas un héritage multiple résoudrait ce problème.

Tout qui dérive d'Object, pas d'héritage multiple... Ça ne donne pas trop envie d'essayer D pour l'instant. Tu parlais d'usages avancés des templates... Tu pourrais détailler ?
1  0 
Avatar de Florian Goo
Membre éclairé https://www.developpez.com
Le 05/12/2009 à 16:07
Remarque, on peut dire la même chose de void*.
Contient-elle seulement des fonctions membres, cette classe Object ?

Edit: Pour D 1.0 j'ai trouvé ça :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Object;
    All D class objects inherit from Object.

    void print();
        Converts Object to human readable text and writes it to stdout.

    char[] toString();
        Convert Object to a human readable string.

    uint toHash();
        Compute hash function for Object.

    int opCmp(Object o);
        Compare with another Object obj.

        Returns:
        this < obj 	< 0
        this == obj 	0
        this > obj 	> 0


    int opEquals(Object o);
        Returns !=0 if this object does have the same contents as obj.

    static Object factory(char[] classname);
        Create instance of class specified by classname. The class must either have no constructors or have a default constructor.

        Returns:
        null if failed
http://www.digitalmars.com/d/1.0/pho...os/object.html

Et pour D 2.0 :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Object;
    All D class objects inherit from Object.

    string toString();
        Convert Object to a human readable string.

    hash_t toHash();
        Compute hash function for Object.

    int opCmp(Object o);
        Compare with another Object obj.

        Returns:
        this < obj 	< 0
        this == obj 	0
        this > obj 	> 0

    equals_t opEquals(Object o);
        Returns !=0 if this object does have the same contents as obj.

    static Object factory(string classname);
        Create instance of class specified by classname. The class must either have no constructors or have a default constructor.

        Returns:
        null if failed
http://www.digitalmars.com/d/2.0/pho...os/object.html
Un peu moins pire (le print() en moins), mais bon…
1  0 
Avatar de koala01
Expert éminent sénior https://www.developpez.com
Le 05/12/2009 à 17:22
Citation Envoyé par metagoto Voir le message
Oui bien sur, on parle de hiérarchie a N niveaux.

Certes, mais tout dériver de Object ne suffit pas à dire qu'on ne respecte pas le LSP. C'est ça le coeur de mon interrogation.
Après, je ne dis pas qu'une telle hiérarchie est meilleur qu'une autre.
Attention, je tiens à préciser que je n'ai jamais dit qu'une hiérarchie basée sur une classe de base unique ne respectait pas LSP...

J'ai bien dit (c'était le sens de ma phrase) qu'une telle hiérarchie prenait, à mon sens, certaines libertés par rapport à LSP.

Et, justement, je me disais que je n'étais pas vraiment allé jusqu'au bout de mon raisonnement... et tu me donne une occasion "unique" de le poursuivre

Nous sommes donc d'accord sur ce qu'implique LSP, et sur le fait qu'il s'applique aux N niveaux d'héritage

Or, le seul ensemble de "propriétés communes" (c'est tout le sens de LSP) que l'on puisse trouver afin de décider (en respectant LSP) de créer une classe ancêtre commune à toutes les autres est... un ensemble vide.

Autrement dit, la classe Object (ou quelle que soit son orthographe) ne fournirait aucun service serait composée plus ou moins comme suit:
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
class Object
{
    public:
        /* même pas besoin de définir un constructeur, celui fournit par
         * le compilateur suffit
         */
        virtual ~Object() /* =0   si on veut s'assurer que la classe en soit
                           * pas instanciée en l'état
                           */;
};
Si tu y réfléchi, tu ne peux simplement rien faire de l'objet, à par décider de le détruire (tu me dira peut être que ce n'est déjà pas "si mal" ).

Mais la conséquence directe, c'est que tu ne peux pas envisager d'utiliser concrètement l'instance d'une classe dérivée de Object sans... passer par un downcast...

Or, c'est là que le bât blesse: si j'admet que le downcast est *parfois* intéressant / utile / nécessaire, j'estime qu'il est mauvais de forcer l'utilisateur à l'utiliser de manière systématique car, dans certains cas, cela force l'utilisateur à mettre en place, par exemple, un pattern "chaine de responsabilités", et donc à complexifier le desing de l'application bien plus que ce qu'il aurait été nécessaire si l'héritage de Object n'avait pas été effectué (forçant l'utilisateur à créer une collection d'objets pris dans le sens moins "générique".

De plus, l'héritage d'une classe commune présente un autre effet de bord, assez particulier: celui de "déporter" une série de responsabilités.

Imaginons une collection d'objets.

Normalement, la collection est sensée savoir quel type d'objet concrets elle doit accepter et renvoyer:

La responsabilité d'accepter d'ajouter un objet à la collection sur base de la cohérence de type devrait, normalement, échoir à... la collection...

De même, lorsque l'on accède à un élément de la collection, nous sommes en droit d'obtenir un objet, à tout le moins, utilisable...

Or, si on crée une collection de Object, non seulement, nous disons à la collection "tu peux tout accepter, y compris de mettre une pomme à coté d'une voiture", mais, en plus, nous déportons la responsabilité de cohérence de type vers la fonction qui devra manipuler la collection... A charge de l'utilisateur de veiller à ce que les types manipulés lors de l'insertion ou de la récupération d'éléments soit cohérent.

A l'insertion, nous pouvons assurer une certaine cohérence de type en décidant d'insérer non pas des instances de Object, mais plutôt des instances de VehiculeAMoteur (incluant certains bateaux, des camions, des voitures et... des trottinettes à moteurs)

A l'utilisation de la collection, ou bien nous nous reposons sur le fait que l'insertion a assuré une certaine cohérence des données (... en espérant que c'est bien le cas), ou bien, nous préférons quand même vérifier que le downcast a réussi, mais, quoi qu'il en soit, nous devons downcaster l'Object récupéré en, par exemple, VehiculeAMoteur, afin de pouvoir "ratisser large" et manipuler certains bateaux, des camions, des voitures ou... des trottinettes à moteurs...

Au passage, je signale qu'il y aurait sans doute également un problème de conception si, l'on décidait de manipuler une collection d'instances de type VehiculeAMoteur alors que l'on souhaite limiter le type aux seules voitures car une même cause aura les même effets: nous devrons downcaster chaque élément avant de pouvoir l'utiliser

Or, justement, LSP a, entre autre, comme conséquence de s'assurer que, quel que soit le type parent que tu décidera de prendre comme base lorsque tu crée une collection, tu puisse utiliser l'interface publique de ce type pour manipuler les éléments de cette collection sans "te poser de question"...

Et il faut avouer que, non seulement, il n'est pas cohérent de permettre (comme le fait la classe Object) de placer des pommes et des voitures dans une même collection, mais, en plus, que l'interface publique de la classe Object est - définitivement - trop légère pour être d'une quelconque utilité.

Voilà en quoi j'estime que la philosophie du "tout objet" prend des liberté par rapport à LSP.
1  0 
Avatar de koala01
Expert éminent sénior https://www.developpez.com
Le 05/12/2009 à 17:29
Citation Envoyé par Florian Goo Voir le message
Remarque, on peut dire la même chose de void*.
Contient-elle seulement des fonctions membres, cette classe Object ?

Edit: Pour D 1.0 j'ai trouvé ça :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Object;
    All D class objects inherit from Object.

    void print();
        Converts Object to human readable text and writes it to stdout.

    char[] toString();
        Convert Object to a human readable string.

    uint toHash();
        Compute hash function for Object.

    int opCmp(Object o);
        Compare with another Object obj.

        Returns:
        this < obj 	< 0
        this == obj 	0
        this > obj 	> 0


    int opEquals(Object o);
        Returns !=0 if this object does have the same contents as obj.

    static Object factory(char[] classname);
        Create instance of class specified by classname. The class must either have no constructors or have a default constructor.

        Returns:
        null if failed
http://www.digitalmars.com/d/1.0/pho...os/object.html

Et pour D 2.0 :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Object;
    All D class objects inherit from Object.

    string toString();
        Convert Object to a human readable string.

    hash_t toHash();
        Compute hash function for Object.

    int opCmp(Object o);
        Compare with another Object obj.

        Returns:
        this < obj 	< 0
        this == obj 	0
        this > obj 	> 0

    equals_t opEquals(Object o);
        Returns !=0 if this object does have the same contents as obj.

    static Object factory(string classname);
        Create instance of class specified by classname. The class must either have no constructors or have a default constructor.

        Returns:
        null if failed
http://www.digitalmars.com/d/2.0/pho...os/object.html
Un peu moins pire (le print() en moins), mais bon…
Je me doute que, au niveau de la classe Object, de nombreuses fonctions ne sont pas définies, ou qu'elles le sont de manière arbitraires...

Mais, si l'on ne fait que regarder l'interface de cette classe, cela signifie qu'il est possible de comparer une pomme à une voiture, et qu'il est possible d'obtenir une chaine de caractères basée sur l'objet.

Je suis désolé, mais, à mon sens, il n'y a, conceptuellement parlant, aucune cohérence ni à vouloir effectuer une telle comparaison, ni à vouloir obtenir une telle chaine de caractères.

Après tout, comme voulez vous convertir une pomme ou une voiture en chaine de caractères "humainement lisible" en "vroum" et en "miam"

[EDIT]J'oubliais: void* n'est pas une classe... c'est un objet de type pointeur dont le type est indéterminé...

Et je suis également contre toute utilisation de ce type de pointeur
1  0 
Avatar de koala01
Expert éminent sénior https://www.developpez.com
Le 05/12/2009 à 18:17
Citation Envoyé par metagoto Voir le message
Ah ben voila, tu pouvais t'arrêter là
Tu aurais au moins pu repsecter mon post, et prendre le paragraphe suivant, qui est à mon sens bien plus important
Ma question initiale dans ce post était candide, et ne se focalisait pas uniquement sur le c++.

Alors sinon, oui je suis d'accord avec toi pour le reste de ton argumentation -dans le cadre du c++.
Le fait est que je ne me focalise pas uniquement sur C++, mais bien sur deux principes de programmation de manière générale que j'estime des plus importants:
  • La règle de la responsabilité unique, qui a une portée tout à fait générale, et, au sujet de laquelle je démontre, effectivement, qu'une optique "tout objet" a tendance à mettre à mal
  • Le principe de substituabilité de liskov, pour lequel il y a une très forte corrélation avec la responsabilité unique, et avec lequel j'estime qu'une optique "tout objet" tend à prendre des libertés

Regarde ce qui se fait en java: quand tu dispose d'une collection (quel qu'en soit le type), tu dois downcaster l'élément de la collection afin de pouvoir l'utiliser "sous sa forme la plus dérivée" (qui est généralement sa forme la plus utile)...

La seule présence de ce downcast montre, pour "naturel" qu'il puisse sembler, à l'évidence, d'autant plus qu'il est systématique, que les concepteurs de java ont "fait fausse route" en décidant de présenter une collection permettant de maintenir ensemble des instances dérivées de Object...

De même, la fonction toString a pour comportement par défaut de fournir une chaine contenant... l'adresse de l'objet...

C'est, quelque part, normal dans le sens où, autrement, l'utilisateur aurait été tenu de redéfinir cette fonction y compris pour les types pour lesquels une telle fonction est inutile / inopportune, mais elle montre clairement que, effectivement, LSP n'est pas respecté en profondeur car on ne peut pas dire que la propriété toString de la classe Object (dont on peut, soit dit en passant déjà se poser la question de la validité pour la classe Object) soit, effectivement, valide pour les classes qui en dérivent...

Maintenant, il ne faut pas croire que je ne vise ici que java: je vise, de manière générale, tous les langages utilisant un principe similaire et, au delà, toute conception qui tendrait à mettre un tel principe en oeuvre
1  0 
Avatar de Alp
Expert éminent sénior https://www.developpez.com
Le 10/12/2009 à 13:26
Citation Envoyé par deadalnix Voir le message
ou C++ avec le void*
Tu dois confondre avec C, ou encore le légendaire "C/C++"

Oui oui, j'ai un médicament pour lutter contre la mauvaise foi... Mais dans le fond je ne pense pas avoir tort. On a rarement recommandé l'utilisation de void* en C++
1  0