12
votes

Pourquoi deux alias à "gamme de chaînes" traitées différemment?

Dans Pascal il y a deux types de déclarations de type:

  • alias de type: type = NouveauNom oldtype em> li>
  • Création de type: type = NewType type strong> oldtype em> li> Ul>

    Le premier est que créer un raccourci pratique, comme typedef em> C. Les alias sont compatibles l'un à l'autre et de leur type d'origine. Les types créés sont volontairement incompatibles et ne peuvent pas être mélangés sans explicite et dangereux par typecast définition. P>

     type T1 = array of string; T2 = array of string;
    
     procedure TForm1.FormCreate(Sender: TObject);
      function Generator: T1;
        begin Result := T1.Create('xxx', 'yyy', 'zzz'); end;
      procedure Consumer (const data: T2);
        begin
          with TStringList.Create do 
          try
            AddStrings(data);
            Self.Caption := CommaText;
          finally
            Free;
          end;
        end;
      begin
        Consumer(Generator);
      end;
    
    • System.Types.TStringDynArray = tableau de chaînes strong>; li>
    • System.TArray = gamme de strong> T;
      • en particulier que des moyens em> tarray = tableau de chaînes strong>; par définition. Em> li> Ul> li> Ul>

        Maintenant, nous allons prendre fonction renvoyant l'ancien alias de type et nourrir son résultat à la fonction attendant ce dernier celui-ci: p>

        uses Classes, IOUtils;
        
         TStringList.Create.AddStrings(
            TDirectory.GetFiles('c:\', '*.dll') );
        
         TStringList.Create.AddStrings(
             TArray<string>( // this is required by compiler - but why ???
                 TDirectory.GetFiles('c:\', '*.dll') ) );
        


1 commentaires

Pas besoin d'apporter des génériques à cela. Essayez type t1 = tableau de chaîne; T2 = tableau de chaîne puis tente d'attribuer une variable de type T1 à l'une de type T2.


3 Réponses :


7
votes

Delphi est une langue fortement typée. Cela signifie que identiques (dans ce cas, je veux dire que leurs définitions ont l'air exactement les mêmes) ne sont pas compatibles.

Lorsque vous écrivez Tableau de code> Vous définissez un type et non un alias . Comme David l'a déjà dit dans son commentaire, les deux types identiques comme p> xxx pré>

ne sont pas compatibles compatibles. P>

même chose pour P>

type
  TStringDynArray = array of string;
  TArray<T> = array of string;


14 commentaires

OOOKAY, Donc, vous faites Tstringdynarray = TARRAY - et pourquoi ils sont devenus une affectation - compatible avec le bleu? Si "types identiques ne sont pas compatibles, cette définition ne devrait pas changer rien. Pourquoi avons-nous windows.dord = system.types.dword; et system.types.dordle = system.longword; et attendez-vous à ce qu'ils soient compatibles? Et quel est le sens de type x = type y de construction gauche? Par "Autres problèmes" U signifie une compatibilité ascendante avec des bibliothèques faites pour les versions antérieures de Delphi? Comme Things Extension n'a pas expliqué que IOUTILS ou vice versa? L'aliénation de type inutile l'a fait!


@ Arioch'the: Désolé, c'était une faute de frappe. Je voulais dire TStringdynarray = TARRAY .


@Arioch: type x = type y crée une nouvelle RTTI pour X. Vous pouvez donc savoir si vous avez un TMYSTRING ou TYOURSTRING avec "=" chaîne de type ". Les types simples sont compatibles avec une affectation. Mais un tableau est un type complexe ("construit") comme un enregistrement.


Tstringdynarray = Tarray ne changerait rien


@DavidHeffernan Oui, il y aurait parce qu'il n'y aurait qu'un seul TARRAY Tapez votre application. Définir t1 = TARRAY et T2 = TARRAY et voyez que les variables de chaque type sont compatibles. Si cela ne serait pas le cas des génériques.Collections.PAS ne compilerait pas.


Oui, je vois que c'est vrai maintenant. dit "Deux génériques instanciés sont considérées comme étant compatibles si les types de base sont identiques ( ou sont des alias à un type commun) et les arguments de type sont identiques. "


Cela pourrait avoir du sens dans Turbopascal, où (1) Tous les tableaux avaient une longueur fixe, (2) U ne pouvait que renvoyer des types simples des fonctions. Pour ce que je me souviens, des types construits ne pouvaient pas être attribués du tout, le compilateur n'a pas su comment le faire. Vous deviez donc utiliser des paramètres var-paramètres et des alias de type unioque. Mais maintenant, il n'y a pas de sens technique dans cela, le compilateur n'est pas si limité maintenant. Et cette restriction inutile dommageait sérieusement la flexibilité de la composition du programme. C'est l'héritage de l'ancien compilateur et il n'y a pas de bien dans cet héritage!


T1 = TARRAY ET T2 = TARRAY est compatible. T1 = Taille de chaîne et T2 = tableau de chaîne ne le sont pas. Et tableau de string = TARRAY . N'a-t-il pas l'impression de schizophrénie?


@Ariamch Si vous définissez deux types différents, même si elles ont l'air de même, il y a une raison pour laquelle vous le faites. Et c'est pourquoi ils ne sont pas compatibles les uns aux autres. Si vous voulez qu'ils soient compatibles, utilisez un type au lieu de 2. Il y a une raison derrière elle. Si tel était comme si vous souhaitez que vous souhaitiez: Aujourd'hui, les deux types sont identiques et le programme compile simplement bien et fonctionne. Demain, l'un des 2 types est changé et que rien ne compile plus.


Regardons le problème d'un angle de plus. Quelle est la raison d'être pour Tarray si elle est incompatible avec tout le code hérité? Peut-être que Delphi définirait mieux la matrice de type de Tarray à la place? Maintenant, dès que vous utilisez Tarray il se tourne vers être islamé, incompatible avec tout le code précédent. Et puis quelle est la valeur de ce type? Utilisez d'anciens bons de bons livres dynamiques et vous avez terminé.


Si vous définissez deux types différents, même si elles ont la même raison, il y a une raison pour laquelle vous le faites. - c'est exactement cela mentionné type TFilename = type chaîne de type construction. Lorsque j'utilise un type simple type - Je ne définit différents types . Delphi fait, ne me laissant aucun choix. Si vous voulez qu'ils soient compatibles, utilisez un type au lieu de 2 même Embarcadero lui-même n'a pas pu le faire. Comment imaginez-vous toute la communauté de différentes années de territoire le ferait? Allez! Nous n'avons toujours pas un vrai incluant avec les versions de l'IFDEF pour le compilateur. Chaque bibliothèque a et maniaque c'est propre. Une telle chose simple!


Maintenant, vous jugez pratique de faire un système de type unifié uniforme un peu? Sans migrer vers CLR / JVM? Avec un soutien aux bibliothèques et compilateurs quelques années d'avant en arrière?


Demain L'un des 2 types se change et la flèche Rien ne compile plus Oui, oui, exactement! Mais c'est pire! Vous me forcez à utiliser des typastes explicites où il n'y a pas besoin pour eux. Donc demain, quand un type change - cela compilerait - mais ne fonctionnerait pas. Delphi applique le développeur pour désactiver la typification! Ou vous pouvez appeler cette "remplacement" doucement. Et quand demain les types couraient vraiment incompatibles - le développeur obtiendrait une sorte de Pansichar (Unicodestring), qui compilerait bien, mais ne fonctionnerait pas.


Ouais, je sens la même chose. Je définis un alias à un autre type et vous prétendiez que j'avais l'intention d'isoler ces types. Je n'étais pas, ne dis pas ce qui ne l'est pas! Mais vous venez de me laisser sans choisir.



11
votes

La clé pour comprendre ce problème est le type compatibilité et identité sujet dans le Guide de la langue. Je suggère que vous ayez une bonne lecture de ce sujet.

Il est également utile de simplifier l'exemple. L'inclusion des génériques dans l'exemple sert principalement à compliquer et à confondre les choses. xxx

de la documentation:

Lorsqu'un identifiant de type est déclaré à l'aide d'un autre identifiant de type, sans qualification, ils désignent le même type.

Ceci signifie que Tinteger1 et Tinteger2 sont le type même le même type que integer .

Un peu plus loin dans la documentation est-ce:

Constructions linguistiques qui fonctionnent comme noms de type indiquent un type différent à chaque fois qu'ils se produisent.

Les déclarations de TARRAY1 et TARRAY2 tomber dans cette catégorie. Et cela signifie que ces deux identifiants désignent différents types.

Nous devons maintenant examiner la section discutant de la compatibilité. Cela donne un ensemble de règles à suivre pour déterminer si deux types sont compatibles ou non compatibles. Nous pouvons en fait raccourci que la discussion en se référant à une autre rubrique d'aide: types structurés, types de réseau et missions qui états clairement:

Les matrices sont compatibles-compatibles uniquement si elles sont du même type.

Ceci indique clairement pourquoi l'affectation array1: = array2 donne une erreur de compilateur.

Votre code a regardé les paramètres de passage, mais la mine axée sur la mission . Les problèmes sont les mêmes car, comme le Procédures et fonctions d'appel Sujet d'aide explique: < BlockQuote>

Lorsque vous appelez une routine, rappelez-vous que:

  • Les expressions utilisées pour passer les paramètres de const et de valeur dactylographiques doivent être compatibles-compatibles avec les paramètres formels correspondants.
  • .......

9 commentaires

Chaque type est compatible avec lui-même. Deux types distincts sont compatibles s'ils répondent au moins une des conditions suivantes. -et LOOOONG Liste des cas spéciaux. Qu'est-ce qui signifie essentiellement? Que les restrictions de l'école de vanille Pascal ou du Turbo Compilateur Turbo au début entrent désormais la composition des programmes réels. Oui, ces types sont formellement différents, mais ils sont pratiquement compatibles. L'exemple affirme créer deux types distincts, TS1 et TS2. mais il prétend qu'ils sont compatibles . Qu'est-ce que c'est ? Il est pratique de nier de constructions formelles. Les tableaux doivent également être compatibles!


Et non, je me soucie peu de fumeur var1: = var2 . Il a peu de sens pratique (pour la plupart des moments). Vous pourriez avoir besoin var1: = expression-with-var2 , mais quelles sont les expressions avec des enregistrements et des tableaux? Ils sont une sorte de fonctions. Mapréduce et tel. Donc, je me soucie de la facilité des fonctions de chaînage, de la source expressif laconique. L'affectation entre Vars ne m'aiderait pas beaucoup, mais lorsque je dois ajouter beaucoup de chaudières, il suffit de combiner deux fonctions standard - c'est des tours cachées sur la piste de course à pied!


"Et non, je me soucie peu de FIRECT VAR1: = VAR2". Pourquoi pas? Le passage des paramètres à une procédure est à peu près la même chose que l'attribution à une variable. Et ainsi, l'affectation-compatibilité est la nuit de la question ici. C'est précisément quelle est votre question. Réécrire mon exemple de code en termes de paramètre passant si vous préférez, les conclusions sont exactement les mêmes. Cela ne répond pas à votre question? Je sais que c'est frustrant pour vous, mais les règles sont les règles et nous ne pouvons pas les changer. Seul EMBA peut les changer.


Passer des paramètres à une procédure est à peu près Oui, dans le même sens que la programmation à Delphi est le nom de la programmation en tant que programmation dans l'assembleur. Toutes les langues de Turing-complètent sont simplement Syntaxe Sugar l'un pour l'autre. Mais dans vraiment je n'utilise pas beaucoup d'affectation directe non-mutating. Cela a juste peu de sens pratique. Mais j'appelle un seul résultat des fonctions d'un autre. Si le compilateur le traite comme Attributant - que ce soit, c'est son choix interne. Je me soucie de la compatibilité = composition des expressions et des fonctions.


Seul EMBA peut les changer. Et nous pouvons élever la question. Nous pouvons demander 'Bonjour! Delphi est à bout d'enfin! Tapez pour passer à autre chose! ' Et le fait que l'EMBA a commis une erreur dans son RTL juste un bon moment pour élever la voix. Comme des commentaires anti-msie sur les sites Microsoft, cette affaire se produit que cette restriction héritée a perdu du sens pratique et que fermer uniquement la productivité. EMBA RTL Architects - Le plus éclairé et expérimenté - Impossible de rendre compte de cette restriction. Si cela ne montre pas à quel point cette restriction est issue de NovaDays, je ne sais pas ce qui peut être.


Les liens de documentation que j'ai fournis expliquent les règles que le compilateur suit. Pourquoi ces règles sont donc si bienvenues à la naissance de Pascal.


Oui, hier j'ai jeté un coup d'œil à "Signaler Pascal" de 1949/1974, et cette règle y attend bien. Pas une telle chose comme "Open Array", vous ne pouvez pas faire Procédure XXX (Liste YY: Array of Byte) ; Tout doit avoir le nom. Et vous seuls les petits petits extraits comme le tri des bulles pour votre travail scolaire, aucun code d'autre, votre propre code d'hier de l'année, alors oui, vous pourriez planifier Al les types de données. En 1949, vous pourriez. Mais aujourd'hui, c'est juste une incohérence.


Il n'y a aucun point à me plaindre. C'est Emba que vous devez parler. Changer TStringDynarray = TARRAY Comme Stefan suggère semblerait être la solution facile pour eux.


J'ai fait, j'ai ouvert le billet QC et j'essaie d'attirer l'attention de la communauté aussi. Pourtant, personne n'a signalé de bon effet de cette restriction. Puissions-nous tous demander à EMBA de changer cela? change systématiquement comme ils l'ont fait avec une matrice ouverte, ne pas le patcher un type après l'autre. Je leur ai demandé, n'hésitez pas à rejoindre QC et à exprimer votre opinion!



2
votes

J'ai aussi eu le même problème avec Delphi, où je voulais transmettre des valeurs d'un tableau identique à un autre. Non seulement j'ai des problèmes « d'incompatibilité » avec deux comme des affectations de tableau, mais je ne pouvais pas utiliser aussi le « Copier () » procédure b>. Pour contourner ce problème, je trouve que je pouvais utiliser un pointeur sur un type b> tableau de tableau de chaînes, au lieu.

Par exemple: p>

New_Two_Dimensional_Fixed_Array[10][1]    


0 commentaires