web-dev-qa-db-fra.com

Pourquoi les langages de programmation, en particulier C, utilisent-ils des accolades et non des carrés?

La définition du "langage C-Style" peut pratiquement être simplifiée jusqu'à "utilise des accolades ({}). "Pourquoi utilisons-nous ce caractère particulier (et pourquoi pas quelque chose de plus raisonnable, comme [], qui ne nécessite pas la touche Maj au moins sur les claviers américains)?

Y a-t-il un avantage réel à la productivité du programmeur qui vient de ces accolades, ou les nouveaux concepteurs de langage devraient-ils chercher des alternatives (c'est-à-dire les gars derrière Python)?

Wikipedia nous dit que C utilise lesdites accolades, mais pas pourquoi. Une déclaration dans un article de Wikipedia sur le Liste des langages de programmation basés sur C suggère que cet élément de syntaxe est quelque peu spécial:

De façon générale, les langages de la famille C sont ceux qui utilisent la syntaxe de bloc de type C (y compris les accolades pour commencer et terminer le bloc) ...

98
SomeKittens

Deux des principales influences de C étaient la famille de langages ALGOL (ALGOL 60 et ALGOL 68) et BCPL (dont C tire son nom).

BCPL a été le premier langage de programmation à accolades, et les accolades ont survécu aux modifications syntaxiques et sont devenues un moyen courant de dénoter les instructions de code source du programme. En pratique, sur des claviers limités de la journée, les programmes source utilisaient souvent les séquences $ (et $) à la place des symboles {et}. Les commentaires sur une seule ligne "//" de BCPL, qui n'ont pas été repris en C, sont réapparus en C++, puis en C99.

De http://www.princeton.edu/~achaney/tmve/wiki100k/docs/BCPL.html

BCPL a introduit et mis en œuvre plusieurs innovations qui sont devenues des éléments assez courants dans la conception de langages ultérieurs. Ainsi, c'était le premier langage de programmation à accolades (celui utilisant {} comme délimiteurs de blocs), et c'était le premier langage à utiliser // pour marquer les commentaires en ligne.

De http://progopedia.com/language/bcpl/

Au sein de BCPL, on voit souvent des accolades, mais pas toujours. C'était une limitation des claviers à l'époque. Les personnages $( et $) étaient lexicographiquement équivalents à { et }. Digraphes et trigraphes ont été conservés en C (bien qu'un ensemble différent pour le remplacement des accolades - ??< et ??>).

L'utilisation d'accolades a été affinée en B (qui a précédé C).

De Référence des utilisateurs à B par Ken Thompson:

/* The following function will print a non-negative number, n, to
  the base b, where 2<=b<=10,  This routine uses the fact that
  in the ASCII character set, the digits 0 to 9 have sequential
  code values.  */

printn(n,b) {
        extern putchar;
        auto a;

        if(a=n/b) /* assignment, not test for equality */
                printn(a, b); /* recursive */
        putchar(n%b + '0');
}

Il y a des indications que les accolades ont été utilisées comme raccourci pour begin et end dans ALGOL.

Je me souviens que vous les avez également inclus dans le code de la carte à 256 caractères que vous avez publié dans CACM, parce que j'ai trouvé intéressant que vous proposiez qu'ils puissent être utilisés à la place des mots clés ALGOL "début" et "fin", ce qui est exactement comment ils ont ensuite été utilisés en langage C.

De http://www.bobbemer.com/BRACES.HTM


L'utilisation de crochets (comme remplacement suggéré dans la question) remonte encore plus loin. Comme mentionné, la famille ALGOL a influencé C. Dans ALGOL 60 et 68 (C a été écrit en 1972 et BCPL en 1966), le crochet a été utilisé pour désigner un index dans un tableau ou une matrice.

BEGIN
  FILE F(KIND=REMOTE);
  EBCDIC ARRAY E[0:11];
  REPLACE E BY "HELLO WORLD!";
  WRITE(F, *, E);
END.

Comme les programmeurs connaissaient déjà les crochets pour les tableaux dans ALGOL et BCPL, et les accolades pour les blocs dans BCPL, il n'y avait pas vraiment besoin ou envie de changer cela lors de la création d'un autre langage.


La question mise à jour comprend un addendum de productivité pour l'utilisation des accolades et mentionne le python. Il y a d'autres ressources qui font cette étude bien que la réponse se résume à "Son anecdotique, et ce à quoi vous êtes habitué, c'est avec quoi vous êtes le plus productif." En raison des compétences très variées en programmation et de la familiarité avec différentes langues, celles-ci deviennent difficiles à prendre en compte.

Voir aussi: Stack Overflow Existe-t-il des études statistiques qui indiquent que Python est "plus productif"?

Une grande partie des gains dépendrait du IDE (ou manque de) utilisé). Dans les éditeurs basés sur vi, en plaçant le curseur sur une ouverture/fermeture correspondante et en appuyant sur % déplacera alors le curseur sur l'autre caractère correspondant. C'est très efficace avec les langages basés sur C dans le passé - moins maintenant.

Une meilleure comparaison serait entre {} et begin/end qui étaient les options du jour (l'espace horizontal était précieux). De nombreuses langues Wirth étaient basées sur un style begin et end (ALGOL (mentionné ci-dessus), Pascal (que beaucoup connaissent) et la famille Modula).

J'ai du mal à en trouver qui isolent cette fonctionnalité de langue spécifique - au mieux, je peux montrer que les langues d'accolade sont beaucoup plus populaires que les langues de début et c'est une construction commune. Comme mentionné dans le lien de Bob Bemer ci-dessus, l'accolade bouclée a été utilisée pour faciliter la programmation en sténographie.

De Pourquoi Pascal n'est pas mon langage de programmation préféré

Les programmeurs C et Ratfor trouvent encombrants 'begin' et 'end' par rapport à {et}.

C'est à peu près tout ce qui peut être dit - sa familiarité et sa préférence.

101
user40980

Bretelles carrées [] sont plus faciles à taper depuis le terminal IBM 2741 qui était "largement utilisé sur Multics" OS, qui à son tour avait Dennis Ritchie, l'un des créateurs du langage C en tant que membre de l'équipe de développement .

http://upload.wikimedia.org/wikipedia/commons/thumb/9/9f/APL-keybd2.svg/600px-APL-keybd2.svg.png

Notez le absence des accolades à la disposition IBM 2741!

En C, les accolades carrées sont "prises" car elles sont utilisées pour les tableaux et les pointeurs . Si les concepteurs de langage s'attendaient à ce que les tableaux et les pointeurs soient plus importants/utilisés plus fréquemment que les blocs de code (ce qui ressemble à une hypothèse raisonnable à leurs côtés, plus sur le contexte historique du style de codage ci-dessous) , cela signifierait que les accolades seraient utilisées dans la syntaxe "moins importante".

L'importance des tableaux est assez évidente dans l'article Le développement du langage C de Ritchie. Il existe même une hypothèse explicite de "prévalence des pointeurs dans les programmes C" .

... nouveau langage a conservé une explication cohérente et réalisable (si inhabituel) de la sémantique des tableaux ... Deux idées sont le plus caractéristique de C parmi les langues de sa classe: la relation entre tableaux et pointeurs ... L'autre trait caractéristique de C, son traitement des tableaux ... a de réelles vertus. Bien que la relation entre les pointeurs et les tableaux soit inhabituelle, elle peut être apprise. De plus, le langage affiche puissance considérable pour décrire des concepts importants, par exemple, des vecteurs dont la longueur varie au moment de l'exécution, avec seulement quelques règles et conventions de base ...


Pour mieux comprendre le contexte historique et le style de codage de l'époque à laquelle le langage C a été créé, il faut tenir compte du fait que "L'origine de C est étroitement liée au développement de l'Unix" et, spécifiquement, le portage du système d'exploitation vers un PDP-11 "a conduit au développement d'une première version de C" ( cite la source ). Selon Wikipedia , "en 1972, Unix a été réécrit dans le langage de programmation C".

Le code source de diverses anciennes versions d'Unix est disponible en ligne, par exemple sur Le site Unix Tree . Parmi les différentes versions qui y sont présentées, la plus pertinente semble être Deuxième édition Unix datée de 1972-06:

La deuxième édition d'Unix a été développée pour le PDP-11 aux Bell Labs par Ken Thompson, Dennis Ritchie et d'autres. Il a étendu la première édition avec plus d'appels système et plus de commandes. Cette édition a également vu le début du langage C, qui a été utilisé pour écrire certaines des commandes ...

Vous pouvez parcourir et étudier le code source C à partir de la page Second Edition Unix (V2) pour avoir une idée du style de codage typique de l'époque.

V2/c/ncc est un exemple important qui soutient l'idée qu'à l'époque il était assez important pour le programmeur de pouvoir taper facilement des crochets. .c code source:

/* C command */

main(argc, argv)
char argv[][]; {
    extern callsys, printf, unlink, link, nodup;
    extern getsuf, setsuf, copy;
    extern tsp;
    extern tmp0, tmp1, tmp2, tmp3;
    char tmp0[], tmp1[], tmp2[], tmp3[];
    char glotch[100][], clist[50][], llist[50][], ts[500];
    char tsp[], av[50][], t[];
    auto nc, nl, cflag, i, j, c;

    tmp0 = tmp1 = tmp2 = tmp3 = "//";
    tsp = ts;
    i = nc = nl = cflag = 0;
    while(++i < argc) {
        if(*argv[i] == '-' & argv[i][1]=='c')
            cflag++;
        else {
            t = copy(argv[i]);
            if((c=getsuf(t))=='c') {
                clist[nc++] = t;
                llist[nl++] = setsuf(copy(t));
            } else {
            if (nodup(llist, t))
                llist[nl++] = t;
            }
        }
    }
    if(nc==0)
        goto nocom;
    tmp0 = copy("/tmp/ctm0a");
    while((c=open(tmp0, 0))>=0) {
        close(c);
        tmp0[9]++;
    }
    while((creat(tmp0, 012))<0)
        tmp0[9]++;
    intr(delfil);
    (tmp1 = copy(tmp0))[8] = '1';
    (tmp2 = copy(tmp0))[8] = '2';
    (tmp3 = copy(tmp0))[8] = '3';
    i = 0;
    while(i<nc) {
        if (nc>1)
            printf("%s:\n", clist[i]);
        av[0] = "c0";
        av[1] = clist[i];
        av[2] = tmp1;
        av[3] = tmp2;
        av[4] = 0;
        if (callsys("/usr/lib/c0", av)) {
            cflag++;
            goto loop;
        }
        av[0] = "c1";
        av[1] = tmp1;
        av[2] = tmp2;
        av[3] = tmp3;
        av[4] = 0;
        if(callsys("/usr/lib/c1", av)) {
            cflag++;
            goto loop;
        }
        av[0] = "as";
        av[1] = "-";
        av[2] = tmp3;
        av[3] = 0;
        callsys("/bin/as", av);
        t = setsuf(clist[i]);
        unlink(t);
        if(link("a.out", t) | unlink("a.out")) {
            printf("move failed: %s\n", t);
            cflag++;
        }
loop:;
        i++;
    }
nocom:
    if (cflag==0 & nl!=0) {
        i = 0;
        av[0] = "ld";
        av[1] = "/usr/lib/crt0.o";
        j = 2;
        while(i<nl)
            av[j++] = llist[i++];
        av[j++] = "-lc";
        av[j++] = "-l";
        av[j++] = 0;
        callsys("/bin/ld", av);
    }
delfil:
    dexit();
}
dexit()
{
    extern tmp0, tmp1, tmp2, tmp3;

    unlink(tmp1);
    unlink(tmp2);
    unlink(tmp3);
    unlink(tmp0);
    exit();
}

getsuf(s)
char s[];
{
    extern exit, printf;
    auto c;
    char t, os[];

    c = 0;
    os = s;
    while(t = *s++)
        if (t=='/')
            c = 0;
        else
            c++;
    s =- 3;
    if (c<=8 & c>2 & *s++=='.' & *s=='c')
        return('c');
    return(0);
}

setsuf(s)
char s[];
{
    char os[];

    os = s;
    while(*s++);
    s[-2] = 'o';
    return(os);
}

callsys(f, v)
char f[], v[][]; {

    extern fork, execv, wait, printf;
    auto t, status;

    if ((t=fork())==0) {
        execv(f, v);
        printf("Can't find %s\n", f);
        exit(1);
    } else
        if (t == -1) {
            printf("Try again\n");
            return(1);
        }
    while(t!=wait(&status));
    if ((t=(status&0377)) != 0) {
        if (t!=9)       /* interrupt */
            printf("Fatal error in %s\n", f);
        dexit();
    }
    return((status>>8) & 0377);
}

copy(s)
char s[]; {
    extern tsp;
    char tsp[], otsp[];

    otsp = tsp;
    while(*tsp++ = *s++);
    return(otsp);
}

nodup(l, s)
char l[][], s[]; {

    char t[], os[], c;

    os = s;
    while(t = *l++) {
        s = os;
        while(c = *s++)
            if (c != *t++) goto ll;
        if (*t++ == '\0') return (0);
ll:;
    }
    return(1);
}

tsp;
tmp0;
tmp1;
tmp2;
tmp3;

Il est intéressant de noter à quel point la motivation pragmatique de choisir des caractères pour dénoter des éléments de syntaxe de langage basés sur leur utilisation dans des applications pratiques ciblées ressemble à la loi de Zipf comme expliqué dans cette formidable réponse ...

la relation observée entre fréquence et longueur est appelée Loi de Zipf

... avec la seule différence que longueur dans l'instruction ci-dessus est remplacé par/généralisé comme vitesse de frappe.

24
gnat

C (et par la suite C++ et C #) a hérité son style de contreventement de son prédécesseur B , qui a été écrit par Ken Thompson (avec des contributions de Dennis Ritchie) en 1969.

Cet exemple provient de la référence des utilisateurs à B de Ken Thompson (via Wikipedia ):

/* The following function will print a non-negative number, n, to
   the base b, where 2<=b<=10,  This routine uses the fact that
   in the ASCII character set, the digits 0 to 9 have sequential
   code values.  */

printn(n,b) {
        extern putchar;
        auto a;

        if(a=n/b) /* assignment, not test for equality */
                printn(a, b); /* recursive */
        putchar(n%b + '0');
}

B lui-même était à nouveau basé sur BCPL , un langage écrit par Martin Richards en 1966 pour le système d'exploitation Multics. Le système de contreventement de B n'utilisait que des accolades rondes, modifiées par des caractères supplémentaires (Exemple d'impression factorielle par Martin Richards, via Wikipedia ):

GET "LIBHDR"

LET START() = VALOF $(
        FOR I = 1 TO 5 DO
                WRITEF("%N! = %I4*N", I, FACT(I))
        RESULTIS 0
)$

AND FACT(N) = N = 0 -> 1, N * FACT(N - 1)

Les accolades utilisées en B et dans les langues suivantes "{...}" sont une amélioration que Ken Thompson a apportée par rapport au style d'accolade composé original dans BCPL "$ (...) $".

1
ProphetV