La liste des changements dans D 2.092. Emprunter Emprunter

Du traducteur. Je ne traduis généralement pas de tels articles, car je n'y vois rien d'intéressant. Ici, deux petites innovations, mais les plus importantes - la prise en charge de la liaison directe des bibliothèques C ++ et le système de propriété et d'emprunt «emprunté» de Rust (la seconde est l'hirondelle DFA, la première est sortie dans GCC10 il y a seulement quelques jours, et Nim y pense aussi comme ça) avec une description. En fait, je n'ai traduit aucune liste fastidieuse et les liens mènent à l'original.

Version précédente de la liste 2.0.91.1 (eng)
Où télécharger

2.092.0 est sorti avec 15 changements importants et 44 corrections de bugs et améliorations. Un grand merci aux 47 contributeurs qui ont rendu cette sortie possible.

Modifications du compilateur


  1. Les commutateurs de ligne de commande -revert = import et -transition = checkimports ont été supprimés
  2. Ajout de la prise en charge du codage (mangling) des noms C ++ GNU ABI
  3. Les constructeurs et destructeurs pour les modules qui ne sont pas externes (D) sont marqués comme obsolètes
  4. Violations DIP25 marquées par défaut Obsolète
  5. Système de propriété et d'emprunt de prototypes pour pointeurs
  6. Ajouté -preview = en option qui transforme la classe de stockage en en périmètre const
  7. Les paramètres Printf et scanf sont maintenant vérifiés pour la conformité avec les spécificateurs de format
  8. La variable d'environnement SOURCE_DATE_EPOCH est désormais prise en charge.

Modifications de l'exécution


  1. TypeInfo_Class/TypeInfo_Interface.isBaseOf C#/Java isAssignableFrom
  2. core.memory.pageSize minimumPageSize


  1. Date.isoWeekYear Date.fromISOWeek std.datetime.date
  2. std.xml
  3. std.digest.digest

Dub


  1. Dub lint --report-file

Une liste complète des corrections et améliorations (Fr.)

Remarque: J'ai des pattes, par conséquent, il n'est pas possible de configurer des liens intra-page corrects à partir de la table des matières pour divulguer les sujets dans l'original, désolé = (

Modifications du compilateur


  1. Les commutateurs de ligne de commande -revert = import et -transition = checkimports ont été supprimés.

    Ces clés n'ont rien fait, et pendant un certain temps, elles ont été marquées comme obsolètes. Le compilateur ne les reconnaîtra plus.
  2. () C++ GNU ABI

    GNU ABI C++11 GCC 5.1. D C++, DMD UDA ( ) gnuAbiTag, core.attribute object ( ). ABI , , ++ . , std::string C++11 (DMD -extern-std={c++11,c++14,c++17}).

    :

    extern(C++):
    @gnuAbiTag("tagOnStruct")
    struct MyStruct {}
    @gnuAbiTag("Multiple", "Tags", "On", "Function")
    MyStruct func();

    gnuAbiTag. ( ). UDA -extern-std=c++11. (-extern-std=c++98) UDA . UDA extern(C++) .
  3. , extern(D) .

    ( ) , extern(D), . , , / , , 479, 479, .

    , , .
  4. DIP25 .

    DIP25 2.067.0, , -preview=dip25. , , DIP1000.

    , , -preview=dip25, -preview=dip25. ( ).

    DIP25 , @ safe . , ref , return , .

    struct Foo
    {
        int x;
        // returning `this.x` escapes a reference to parameter `this`, perhaps annotate with `return`
        ref int method() /* return */ { return this.x; }
    }
    // returning `v` escapes a reference to parameter `v`, perhaps annotate with `return`
    ref int identity(/* return */ ref int v) { return v; }

    return . DIP25 .
  5. -preview=in in scope const.

    const scope, in . , in (. inout ) .

    -preview=in, :

    void fun(in int x);
    void fun(const int x);

    -preview=in, :

    void fun(in int x);
    void fun(scope const int x);
  6. printf scanf

    C99 7.19.6.1 printf 7.19.6.2 scanf.

    printf , . , .

    scanf .

    :

    1. ,
    2. ,
    3. — , s
    4. C99

    -, .

    .

    , printf/scanf, :

    printf("%k\n", value);  // error: non-Standard format k
    const format = "%k\n";
    printf(format.ptr, value);  // no error

    — . ,

    string s;
    printf("%.*s\n", s.length, s.ptr);
    printf("%d\n", s.sizeof);
    ulong u;
    scanf("%lld%*c\n", &u);

    :

    string s;
    printf("%.*s\n", cast(int) s.length, s.ptr);
    printf("%zd\n", s.sizeof);
    ulong u;
    scanf("%llu%*c\n", &u);

    printf scanf pragma(printf) printf pragma(scanf) scanf.

    , :

    1. extern (C ) extern (C++)
    2. const(char)*
    3. … -v , va_list ( «v» printf scanf)
    .

    «v»- .
  7. SOURCE_DATE_EPOCH

    SOURCE_DATE_EPOCH. UNIX ( 1970-01-01 00:00:00), . DMD __DATE__, __TIME__ __TIMESTAMP__ .



Le système de propriété / emprunt (également appelé OB) pour les pointeurs garantit que les pointeurs déréférencés pointent vers un objet mémoire valide.

Portée du prototype de système OB


Il s'agit d'un prototype du système OB, adapté pour D. Initialement, il est destiné uniquement aux pointeurs, et non aux tableaux dynamiques, aux références de classe, aux références ou aux champs de pointeur dans les agrégats. L'ajout d'un support de ce type compliquera la mise en œuvre, mais ne change pas son essence, par conséquent, il est reporté pour plus tard. Les objets RAII peuvent gérer en toute sécurité leur propre mémoire, ils ne sont donc pas couverts par l'OB. Quelle que soit la méthode, que le pointeur alloue de la mémoire à l'aide de GC ou d'un autre allocateur, cela n'est pas important pour OB, ils ne diffèrent pas et sont traités de manière identique.

Le système OB n'est actif que dans les fonctions annotées avec l'attribut @ live. Il est appliqué après traitement sémantique uniquement comme contrôle de violation des règles des substances organiques. Aucune nouvelle syntaxe n'est ajoutée. Aucune modification n'est apportée au code généré. Si les fonctions @ live appellent des fonctions autres que @ live , il est prévu que ces fonctions appelées soient une interface compatible @ live , bien qu'elle ne soit pas testée. Si des fonctions non @ live appellent des fonctions @ live , les arguments transmis doivent suivre les conventions @ live .

Le système OB détecte les erreurs:

  • déréférencer les pointeurs qui sont dans un état non valide
  • plusieurs pointeurs actifs vers un objet mémoire muté.

Il ne détectera pas les tentatives de déréférencement d'un pointeur nul ou, potentiellement, d'un pointeur nul. Cela ne fonctionne pas, car il n'existe actuellement aucune méthode pour annoter un type en tant que pointeur non nullable.

Le principe de base de l'OB


La conception de l'OB découle du principe suivant:

pour chaque objet mémoire, il peut y avoir exactement un pointeur de mutation ou plusieurs pointeurs non mutants (en lecture seule).

Conception


Un pointeur mutant unique est appelé le "propriétaire" de l'objet mémoire. Il possède transitoirement un objet mémoire et tous les objets en mémoire accessibles depuis celui-ci (c'est-à-dire le graphe des objets). Puisqu'il est le seul pointeur vers cet objet mémoire, il peut gérer la mémoire en toute sécurité (changer sa forme, allouer, libérer et redimensionner) sans assommer le sol sous les pieds des autres pointeurs (mutants ou non) qui peuvent y être (graphique mémoire) indiquent.

S'il existe plusieurs pointeurs vers un graphique d'objets en mémoire qui sont en lecture seule, ils peuvent le lire en toute sécurité sans se soucier des changements soudains dans le graphique des objets en mémoire.

Les autres détails de la technologie concernent la façon dont les pointeurs deviennent en lecture seule et invalides, et comment le principe de base de l’OB est constamment maintenu.

Pointeurs suivis
Seuls les pointeurs déclarés dans la fonction @ live comme ceci , les paramètres de fonction ou les variables locales sont suivis . Les variables provenant d'autres fonctions ne sont pas suivies, même @ live , car l'analyse des interactions avec d'autres fonctions ne dépend complètement que de la signature de cette fonction, et non de ses internes. Les paramètres const ne sont pas suivis.

États du
pointeur Chaque pointeur se trouve dans l'un des états suivants:

Non défini
Le pointeur est dans un état non valide. Déréférencer un tel pointeur est une erreur.
Propriétaire Le
propriétaire est le seul pointeur vers un graphique d'objets en mémoire. Généralement, un pointeur - le propriétaire n'a pas d'attribut de portée . Si le pointeur avec l'attribut scope est initialisé avec une expression qui n'est pas dérivée du pointeur suivi, il devient alors le propriétaire.
Si le pointeur Propriétaire est affecté à un autre pointeur - le Propriétaire, le premier passe à l'état Non défini.
Emprunté
Un pointeur emprunté est un pointeur qui devient temporairement le seul pointeur sur un graphe d'objets mémoire. Il passe dans cet état grâce à l'affectation du pointeur - le propriétaire, tandis que le propriétaire passe à l'état de l'emprunteur jusqu'à ce que l'utilisation du pointeur emprunté soit terminée.
Un pointeur emprunté doit avoir un attribut scope et être un pointeur vers un objet mutable.
Lecture
seule L' index en lecture seule est attribué par le propriétaire. Tant que le pointeur en lecture seule est actif, seuls les pointeurs en lecture seule peuvent toujours être attribués à partir de ce propriétaire. Le pointeur en lecture seule doit avoir un attribut scope , et il ne doit pas non plus être un pointeur vers un objet mutable.

Durée de vie

La durée de vie de l'indicateur "Emprunté" ou "Lecture seule" commence au moment où il est déréférencé pour la première fois (et non au moment où il est initialisé ou auquel une valeur a été attribuée) et se termine lorsque la valeur est déréférencée en dernier.

Il est également connu sous le nom de durée de vie non lexicale .

Transitions d'état pour les pointeurs

Un pointeur change son état lorsqu'une de ces opérations est effectuée:

  • de la mémoire lui est allouée (par exemple, une variable locale sur la pile), ce qui place le pointeur dans un état non défini
  • initialisation (considérée comme affectation)
  • affectation - les pointeurs source et cible changent d'état en fonction de l'état dans lequel ils se trouvent, ainsi que de leurs types et classes de stockage
  • out ( ), , .
  • ref , , .
  • , .
  • - ()
  • , , .
  • , ,
  • , ,
  • ,


En tant que prototype, de nombreux aspects n'ont pas encore été pris en compte et ne le seront que lorsque le prototype montrera qu'il s'agit d'une solution viable.

Erreurs

Attendez-vous à de nombreuses erreurs. Veuillez les signaler à bugzilla et étiqueter avec le mot clé "ob". Il n'est pas nécessaire de signaler d'autres restrictions déjà répertoriées ici.

Les références aux classes et aux tableaux associatifs ne sont pas suivies.
Ils sont censés être contrôlés par le GC.

L'emprunt et la lecture de non-propriétaires

sont surveillés pour les fuites, mais pas d'autres indicateurs. Les emprunteurs sont considérés comme propriétaires s'ils ne sont pas initialisés avec un pointeur.

@live void uhoh()
{
    scope p = malloc();  // p is considered an Owner
    scope const pc = malloc(); // pc is not considered an Owner
} // dangling pointer pc is not detected on exit

Il semblerait que cela n'a aucun sens de marquer des pointeurs tels que la portée , peut-être que cela peut être corrigé en traitant cela comme une erreur.

Les pointeurs sont lus / écrits par des fonctions imbriquées
.

@live void ohno()
{
    auto p = malloc();

    void sneaky() { free(p); }

    sneaky();
    free(p);  // double free not detected
}



L'analyse des exceptions suppose que les exceptions ne sont pas levées.

@live void leaky()
{
    auto p = malloc();
    pitcher();  // throws exception, p leaks
    free(p);
}

Une solution consiste à utiliser scope (exit) :

@live void waterTight()
{
    auto p = malloc();
    scope(exit) free(p);
    pitcher();
}

utiliser des objets RAII ou appeler uniquement des fonctions de non-retour.

Paramètres paresseux

Non pris en compte.

Complexité quadratique L'

analyse montre la complexité quadratique, essayez de garder les fonctions @ live petites.

Mélanger différents groupes de mémoire

Combiner différents pools de mémoire:

void* xmalloc(size_t);
void xfree(void*);

void* ymalloc(size_t);
void yfree(void*);

auto p = xmalloc(20);
yfree(p);  // should call xfree() instead

non-détecté.

Cela peut être contourné en utilisant des pools spécifiques à un type particulier:

U* umalloc();
void ufree(U*);

V* vmalloc();
void vfree(V*);

auto p = umalloc();
vfree(p);  // type mismatch

et éventuellement interdire les conversions implicites à void * dans les fonctions @ live .

Arguments d'une fonction variadique

Les arguments d'une fonction variadique (par exemple, printf) sont considérés comme consommés. Bien que cela soit sûr, cela ne semble pas très pratique et nécessitera probablement un examen.

Modifications de l'exécution


  1. TypeInfo_Class/TypeInfo_Interface.isBaseOf C#/Java isAssignableFrom.

    TypeInfo_Class.isBaseOf true, , , , . isBaseOf, isAssignableFrom, , opAssign D — . TypeInfo_Interface.isBaseOf , TypeInfo_Class, TypeInfo_Interface.
  2. core.memory.pageSize minimumPageSize.

    pageSize .

    import core.memory : pageSize;
    ubyte[] buffer = new ubyte[pageSize];

    minimumPageSize .

    , . , . pageSize, .

    , , , : ubyte[minimumPageSize].

    import core.memory : minimumPageSize;
    ubyte[minimumPageSize] buffer;



  1. Date.isoWeekYear Date.fromISOWeek std.datetime.date

    ISO 8601 , Date and DateTime.

    ISO , . Date.fromISOWeek(2020, 11, DayOfWeek.mon) Date(2020, 3, 9).

    ISO , () .isoWeekYear Date ISO. , .isoWeekAndYear , .
  2. std.xml .

    std.xml . , , UndeaD. xml dub- dxml.
  3. std.digest.digest .

    2.076.1 . std.digest .

    std.digest.digest 2.101.

Dub


  1. .

    Posix , .dub. dub (, .swap.file.d), . , dub . , dub.

    , .
  2. Dub lint --report-file.

    Dub lint --report-file: dub lint --report-file report.json

All Articles