{"id":327,"date":"2023-06-12T08:49:00","date_gmt":"2023-06-12T08:49:00","guid":{"rendered":"https:\/\/jorgeturiel.es\/?p=327"},"modified":"2023-03-20T13:54:00","modified_gmt":"2023-03-20T13:54:00","slug":"introduccion-al-lenguaje-pascal-moderno-para-programadores-parte-7","status":"publish","type":"post","link":"https:\/\/jorgeturiel.es\/?p=327","title":{"rendered":"Introducci\u00f3n al lenguaje Pascal moderno para programadores (Parte 7)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Funciones varias del lenguaje<\/h2>\n\n\n\n<p id=\"block-5521090e-ab25-4c7d-8ff9-7b06a21f4a1b\">Continuamos con la introducci\u00f3n al lenguaje Pascal Moderno.<\/p>\n\n\n\n<p id=\"block-404f08e6-e309-4eb0-84cf-cdf990136039\">Esta entrada es una traducci\u00f3n al espa\u00f1ol, del texto <a rel=\"noreferrer noopener\" href=\"https:\/\/castle-engine.io\/modern_pascal\" target=\"_blank\">original<\/a> escrito por Michalis Kamburelis.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Rutinas locales (anidadas)<\/h2>\n\n\n\n<p>Dentro de una rutina m\u00e1s grande (funci\u00f3n, procedimiento, m\u00e9todo) puede definir una rutina auxiliar.<\/p>\n\n\n\n<p>La rutina local puede acceder libremente (leer y escribir) a todos los par\u00e1metros de un padre y a todas las variables locales del padre que se declararon sobre \u00e9l. Esto es muy poderoso. A menudo permite dividir rutinas largas en un par de peque\u00f1as sin mucho esfuerzo (ya que no tiene que pasar toda la informaci\u00f3n necesaria en los par\u00e1metros). Tenga cuidado de no abusar de esta caracter\u00edstica\u2009\u2014\u2009si muchas funciones anidadas usan (e incluso cambian) la misma variable del padre, el c\u00f3digo puede ser dif\u00edcil de seguir.<\/p>\n\n\n\n<p>Estos dos ejemplos son equivalentes:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">function SumOfSquares(const N: Integer): Integer;\n\n  function Square(const Value: Integer): Integer;\n  begin\n    Result := Value * Value;\n  end;\n\nvar\n  I: Integer;\nbegin\n  Result := 0;\n  for I := 0 to N do\n    Result := Result + Square(I);\nend;<\/pre><\/div>\n\n\n\n<p>Otra versi\u00f3n, donde dejamos que la rutina local Square acceda directamente a I:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">function SumOfSquares(const N: Integer): Integer;\nvar\n  I: Integer;\n\n  function Square: Integer;\n  begin\n    Result := I * I;\n  end;\n\nbegin\n  Result := 0;\n  for I := 0 to N do\n    Result := Result + Square;\nend;<\/pre><\/div>\n\n\n\n<p>Las rutinas locales pueden llegar a cualquier profundidad\u2009\u2014\u2009lo que significa que puede definir una rutina local dentro de otra rutina local. As\u00ed que puedes volverte loco (pero no te vuelvas loco demasiado, o el c\u00f3digo se volver\u00e1 ilegible :).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Callbacks (tambi\u00e9n conocidos como eventos, tambi\u00e9n conocidos como punteros a funciones, tambi\u00e9n conocidos como variables de procedimiento)<\/h2>\n\n\n\n<p>Permiten llamar a una funci\u00f3n de forma indirecta, a trav\u00e9s de una variable. La variable se puede asignar en tiempo de ejecuci\u00f3n para apuntar a cualquier funci\u00f3n con tipos de par\u00e1metros coincidentes y tipos de devoluci\u00f3n.<\/p>\n\n\n\n<p>La devoluci\u00f3n de llamada puede ser:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Normal, lo que significa que puede apuntar a cualquier rutina normal (no un m\u00e9todo, no local).<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n\nfunction Add(const A, B: Integer): Integer;\nbegin\n  Result := A + B;\nend;\n\nfunction Multiply(const A, B: Integer): Integer;\nbegin\n  Result := A * B;\nend;\n\ntype\n  TMyFunction = function (const A, B: Integer): Integer;\n\nfunction ProcessTheList(const F: TMyFunction): Integer;\nvar\n  I: Integer;\nbegin\n  Result := 1;\n  for I := 2 to 10 do\n    Result := F(Result, I);\nend;\n\nvar\n  SomeFunction: TMyFunction;\nbegin\n  SomeFunction := @Add;\n  WriteLn('1 + 2 + 3 ... + 10 = ', ProcessTheList(SomeFunction));\n\n  SomeFunction := @Multiply;\n  WriteLn('1 * 2 * 3 ... * 10 = ', ProcessTheList(SomeFunction));\nend.<\/pre><\/div>\n\n\n\n<p>Un m\u00e9todo: declarar con el objeto al final.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  TMyMethod = procedure (const A: Integer) of object;\n\n  TMyClass = class\n    CurrentValue: Integer;\n    procedure Add(const A: Integer);\n    procedure Multiply(const A: Integer);\n    procedure ProcessTheList(const M: TMyMethod);\n  end;\n\nprocedure TMyClass.Add(const A: Integer);\nbegin\n  CurrentValue := CurrentValue + A;\nend;\n\nprocedure TMyClass.Multiply(const A: Integer);\nbegin\n  CurrentValue := CurrentValue * A;\nend;\n\nprocedure TMyClass.ProcessTheList(const M: TMyMethod);\nvar\n  I: Integer;\nbegin\n  CurrentValue := 1;\n  for I := 2 to 10 do\n    M(I);\nend;\n\nvar\n  C: TMyClass;\nbegin\n  C := TMyClass.Create;\n  try\n    C.ProcessTheList(@C.Add);\n    WriteLn('1 + 2 + 3 ... + 10 = ', C.CurrentValue);\n\n    C.ProcessTheList(@C.Multiply);\n    WriteLn('1 * 2 * 3 ... * 10 = ', C.CurrentValue);\n  finally\n    FreeAndNil(C);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que no puede pasar procedimientos\/funciones globales como m\u00e9todos. Son incompatibles. Si tiene que proporcionar una devoluci\u00f3n de llamada de objeto, pero no desea crear una instancia de clase ficticia, puede pasar los m\u00e9todos de clase como m\u00e9todos.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyMethod = function (const A, B: Integer): Integer of object;\n\n  TMyClass = class\n    class function Add(const A, B: Integer): Integer\n    class function Multiply(const A, B: Integer): Integer\n  end;\n\nvar\n  M: TMyMethod;\nbegin\n  M := @TMyClass(nil).Add;\n  M := @TMyClass(nil).Multiply;\nend;<\/pre><\/div>\n\n\n\n<p>Desafortunadamente, debe escribir feo @TMyClass(nil).Add en lugar de solo @TMyClass.Add.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Una (posiblemente) rutina local: declare with est\u00e1 anidada al final, y aseg\u00farese de usar la directiva {$modeswitch nestedprocvars} para el c\u00f3digo. Estos van de la mano con las rutinas locales (anidadas).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Gen\u00e9ricos<\/h2>\n\n\n\n<p>Una poderosa caracter\u00edstica de cualquier lenguaje moderno. La definici\u00f3n de algo (t\u00edpicamente, de una clase) se puede parametrizar con otro tipo. El ejemplo m\u00e1s t\u00edpico es cuando necesitas crear un contenedor (una lista, diccionario, \u00e1rbol, gr\u00e1fico\u2026\u200b): puedes definir una lista de tipo T, y luego especializarla para obtener instant\u00e1neamente una lista de enteros, una lista de cadenas , una lista de TMyRecord, etc.<\/p>\n\n\n\n<p>Los gen\u00e9ricos en Pascal funcionan de forma muy similar a los gen\u00e9ricos en C++. Lo que significa que se \u00abexpanden\u00bb en el momento de la especializaci\u00f3n, un poco como las macros (pero mucho m\u00e1s seguras que las macros; por ejemplo, los identificadores se resuelven en el momento de la definici\u00f3n gen\u00e9rica, no en la especializaci\u00f3n, por lo que no puede \u00abinyectar\u00bb nada inesperado). comportamiento al especializar el gen\u00e9rico). En efecto, esto significa que son muy r\u00e1pidos (pueden optimizarse para cada tipo en particular) y funcionan con tipos de cualquier tama\u00f1o. Puede usar un tipo primitivo (entero, flotante), as\u00ed como un registro, as\u00ed como una clase al especializar un gen\u00e9rico.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  generic TMyCalculator&lt;T&gt; = class\n    Value: T;\n    procedure Add(const A: T);\n  end;\n\nprocedure TMyCalculator.Add(const A: T);\nbegin\n  Value := Value + A;\nend;\n\ntype\n  TMyFloatCalculator = specialize TMyCalculator&lt;Single&gt;;\n  TMyStringCalculator = specialize TMyCalculator&lt;string&gt;;\n\nvar\n  FloatCalc: TMyFloatCalculator;\n  StringCalc: TMyStringCalculator;\nbegin\n  FloatCalc := TMyFloatCalculator.Create;\n  try\n    FloatCalc.Add(3.14);\n    FloatCalc.Add(1);\n    WriteLn('FloatCalc: ', FloatCalc.Value:1:2);\n  finally\n    FreeAndNil(FloatCalc);\n  end;\n\n  StringCalc := TMyStringCalculator.Create;\n  try\n    StringCalc.Add('something');\n    StringCalc.Add(' more');\n    WriteLn('StringCalc: ', StringCalc.Value);\n  finally\n    FreeAndNil(StringCalc);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Los gen\u00e9ricos no se limitan a las clases, tambi\u00e9n puede tener funciones y procedimientos gen\u00e9ricos:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\n{ Note: this example requires FPC 3.1.1 (will not compile with FPC 3.0.0 or older). }\n\ngeneric function Min&lt;T&gt;(const A, B: T): T;\nbegin\n  if A &lt; B then\n    Result := A else\n    Result := B;\nend;\n\nbegin\n  WriteLn('Min (1, 0): ', specialize Min&lt;Integer&gt;(1, 0));\n  WriteLn('Min (3.14, 5): ', specialize Min&lt;Single&gt;(3.14, 5):1:2);\n  WriteLn('Min (''a'', ''b''): ', specialize Min&lt;string&gt;('a', 'b'));\nend.<\/pre><\/div>\n\n\n\n<p>Consulte tambi\u00e9n los Contenedores (listas, diccionarios) que usan gen\u00e9ricos sobre clases est\u00e1ndar importantes que usan gen\u00e9ricos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sobrecarga<\/h2>\n\n\n\n<p>Se permiten m\u00e9todos (y funciones y procedimientos globales) con el mismo nombre, siempre que tengan par\u00e1metros diferentes. En tiempo de compilaci\u00f3n, el compilador detecta cu\u00e1l desea usar, sabiendo los par\u00e1metros que pasa.<\/p>\n\n\n\n<p>De forma predeterminada, la sobrecarga utiliza el enfoque FPC, lo que significa que todos los m\u00e9todos en un espacio de nombres dado (una clase o una unidad) son iguales y ocultan los otros m\u00e9todos en espacios de nombres con menos prioridad. Por ejemplo, si define una clase con los m\u00e9todos Foo(Integer) y Foo(string), y desciende de una clase con el m\u00e9todo Foo(Float), entonces los usuarios de su nueva clase no podr\u00e1n acceder al m\u00e9todo Foo( Float) f\u00e1cilmente (todav\u00eda pueden &#8212; si encasillan la clase a su tipo de antepasado). Para superar esto, utilice la palabra clave de sobrecarga.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preprocesado<\/h2>\n\n\n\n<p>Puede usar directivas de preprocesador simples para:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>compilaci\u00f3n condicional (c\u00f3digo dependiendo de la plataforma, o algunos modificadores personalizados)<\/li>\n\n\n\n<li>incluir un archivo en otro<\/li>\n\n\n\n<li>tambi\u00e9n puede utilizar macros sin par\u00e1metros.<\/li>\n<\/ul>\n\n\n\n<p>Tenga en cuenta que no se permiten macros con par\u00e1metros. En general, debe evitar usar el preprocesador\u2026 a menos que est\u00e9 realmente justificado. El procesamiento previo ocurre antes del an\u00e1lisis, lo que significa que puede \u00abromper\u00bb la sintaxis normal del lenguaje Pascal. Esta es una caracter\u00edstica poderosa, pero tambi\u00e9n algo sucia.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit PreprocessorStuff;\ninterface\n\n{$ifdef FPC}\n{ This is only defined when compiled by FPC, not other compilers (like Delphi). }\nprocedure Foo;\n{$endif}\n\n{ Define a NewLine constant. Here you can see how the normal syntax of Pascal\n  is \"broken\" by preprocessor directives. When you compile on Unix\n  (includes Linux, Android, macOS), the compiler sees this:\n\n    const NewLine = #10;\n\n  When you compile on Windows, the compiler sees this:\n\n    const NewLine = #13#10;\n\n  On other operating systems, the code will fail to compile,\n  because a compiler sees this:\n\n    const NewLine = ;\n\n  It's a *good* thing that the compilation fails in this case -- if you\n  will have to port the program to an OS that is not Unix, not Windows,\n  you will be reminded by a compiler to choose the newline convention\n  on that system. }\n\nconst\n  NewLine =\n    {$ifdef UNIX} #10 {$endif}\n    {$ifdef MSWINDOWS} #13#10 {$endif} ;\n\n{$define MY_SYMBOL}\n\n{$ifdef MY_SYMBOL}\nprocedure Bar;\n{$endif}\n\n{$define CallingConventionMacro := unknown}\n{$ifdef UNIX}\n  {$define CallingConventionMacro := cdecl}\n{$endif}\n{$ifdef MSWINDOWS}\n  {$define CallingConventionMacro := stdcall}\n{$endif}\nprocedure RealProcedureName; CallingConventionMacro; external 'some_external_library';\n\nimplementation\n\n{$include some_file.inc}\n\/\/ $I is just a shortcut for $include\n{$I some_other_file.inc}\n\nend.<\/pre><\/div>\n\n\n\n<p>Los archivos de inclusi\u00f3n tienen com\u00fanmente la extensi\u00f3n .inc y se usan para dos prop\u00f3sitos:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>El archivo de inclusi\u00f3n solo puede contener otras directivas del compilador, que \u00abconfiguran\u00bb su c\u00f3digo fuente. Por ejemplo, podr\u00eda crear un archivo myconfig.inc con estos contenidos:<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}\n{$H+}\n{$J-}\n{$modeswitch advancedrecords}\n{$ifndef VER3}\n  {$error This code can only be compiled using FPC version at least 3.x.}\n{$endif}\n<\/pre><\/div>\n\n\n\n<p>Ahora puede incluir este archivo usando {$I myconfig.inc} en todas sus fuentes.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>El otro uso com\u00fan es dividir una unidad grande en muchos archivos, y al mismo tiempo mantenerla en una sola unidad en lo que respecta a las reglas del idioma. No abuse de esta t\u00e9cnica\u2009\u2014\u2009su primer instinto debe ser dividir una sola unidad en m\u00faltiples unidades, no dividir una sola unidad en m\u00faltiples archivos de inclusi\u00f3n. Sin embargo, esta es una t\u00e9cnica \u00fatil.\n<ol class=\"wp-block-list\">\n<li>Permite evitar la \u00abexplosi\u00f3n\u00bb del n\u00famero de unidades, al mismo tiempo que mantiene cortos los archivos de c\u00f3digo fuente. Por ejemplo, puede ser mejor tener una sola unidad con \u00abcontroles de interfaz de usuario de uso com\u00fan\u00bb que crear una unidad para cada clase de control de interfaz de usuario, ya que este \u00faltimo enfoque har\u00eda que la cl\u00e1usula t\u00edpica de \u00abusos\u00bb fuera larga (ya que un c\u00f3digo de interfaz de usuario t\u00edpico dependen de un par de clases de interfaz de usuario). Pero colocar todas estas clases de interfaz de usuario en un solo archivo myunit.pas lo convertir\u00eda en un archivo largo, dif\u00edcil de navegar, por lo que dividirlo en varios archivos de inclusi\u00f3n puede tener sentido.<\/li>\n\n\n\n<li>Permite tener una interfaz de unidad multiplataforma con implementaci\u00f3n dependiente de la plataforma f\u00e1cilmente. B\u00e1sicamente puedes hacer<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$ifdef UNIX} {$I my_unix_implementation.inc} {$endif}\n{$ifdef MSWINDOWS} {$I my_windows_implementation.inc} {$endif}<\/pre><\/div>\n\n\n\n<p>A veces, esto es mejor que escribir un c\u00f3digo largo con muchos {$ifdef UNIX}, {$ifdef MSWINDOWS} mezclados con c\u00f3digo normal (declaraciones de variables, implementaci\u00f3n de rutinas). El c\u00f3digo es m\u00e1s legible de esta manera. Incluso puede usar esta t\u00e9cnica de manera m\u00e1s agresiva, usando la opci\u00f3n de l\u00ednea de comandos -Fi de FPC para incluir algunos subdirectorios solo para plataformas espec\u00edficas. Luego puede tener muchas versiones del archivo de inclusi\u00f3n {$I my platform_specific_implementation.inc} y simplemente incluirlas, permitiendo que el compilador encuentre la versi\u00f3n correcta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Registros<\/h2>\n\n\n\n<p>Record es solo un contenedor para otras variables. Es como una clase mucho m\u00e1s simplificada: no hay herencia ni m\u00e9todos virtuales. Es como una estructura en lenguajes tipo C<\/p>\n\n\n\n<p>Si usa la directiva {$modeswitch advancedrecords}, los registros pueden tener m\u00e9todos y especificadores de visibilidad. En general, las caracter\u00edsticas del idioma que est\u00e1n disponibles para las clases y que no rompen el dise\u00f1o de memoria predecible simple de un registro, son posibles.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$modeswitch advancedrecords}\ntype\n  TMyRecord = record\n  public\n    I, Square: Integer;\n    procedure WriteLnDescription;\n  end;\n\nprocedure TMyRecord.WriteLnDescription;\nbegin\n  WriteLn('Square of ', I, ' is ', Square);\nend;\n\nvar\n  A: array [0..9] of TMyRecord;\n  R: TMyRecord;\n  I: Integer;\nbegin\n  for I := 0 to 9 do\n  begin\n    A[I].I := I;\n    A[I].Square := I * I;\n  end;\n\n  for R in A do\n    R.WriteLnDescription;\nend.<\/pre><\/div>\n\n\n\n<p>En el Object Pascal moderno, su primer instinto deber\u00eda ser dise\u00f1ar una clase, no un registro, porque las clases est\u00e1n repletas de funciones \u00fatiles, como constructores y herencia.<\/p>\n\n\n\n<p>Pero los registros siguen siendo muy \u00fatiles cuando necesita velocidad o un dise\u00f1o de memoria predecible:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Los registros no tienen ning\u00fan constructor o destructor. Simplemente define una variable de un tipo de registro. Tiene contenidos indefinidos (basura de memoria) al principio (excepto los tipos administrados autom\u00e1ticamente, como cadenas; se garantiza que se inicializar\u00e1n para estar vac\u00edos y se finalizar\u00e1n para liberar el recuento de referencias). Por lo tanto, debe tener m\u00e1s cuidado cuando se trata de registros, pero le brinda cierta ganancia de rendimiento.<\/li>\n\n\n\n<li>Las matrices de registros son muy lineales en la memoria, por lo que son compatibles con la memoria cach\u00e9.<\/li>\n\n\n\n<li>El dise\u00f1o de la memoria de los registros (tama\u00f1o, relleno entre campos) est\u00e1 claramente definido en algunas situaciones: cuando solicita el dise\u00f1o C o cuando utiliza un registro empaquetado. Esto es \u00fatil:\n<ul class=\"wp-block-list\">\n<li>para comunicarse con bibliotecas escritas en otros lenguajes de programaci\u00f3n, cuando exponen una API basada en registros<\/li>\n\n\n\n<li>para leer y escribir archivos binarios<\/li>\n\n\n\n<li>para hacer trucos sucios de bajo nivel (como encasillar inseguro un tipo a otro, ser consciente de su representaci\u00f3n de memoria).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Los registros tambi\u00e9n pueden tener partes de casos, que funcionan como uniones en lenguajes similares a C. Permiten tratar la misma pieza de memoria como de un tipo diferente, seg\u00fan sus necesidades. Como tal, esto permite una mayor eficiencia de la memoria en algunos casos. Y permite m\u00e1s trucos inseguros sucios y de bajo nivel \ud83d\ude42<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"> Objetos al estilo antiguo<\/h2>\n\n\n\n<p>En los viejos tiempos, Turbo Pascal introdujo otra sintaxis para la funcionalidad de clase, utilizando la palabra clave de objeto. Es algo as\u00ed como una mezcla entre el concepto de un disco y una clase moderna.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Los objetos de estilo antiguo se pueden asignar\/liberar, y durante esa operaci\u00f3n puede llamar a su constructor\/destructor.<\/li>\n\n\n\n<li>Pero tambi\u00e9n pueden declararse y usarse simplemente, como registros. Un registro simple o un tipo de objeto no es una referencia (puntero) a algo, son simplemente los datos. Esto los hace c\u00f3modos para datos peque\u00f1os, donde la asignaci\u00f3n de llamadas \/ gratis ser\u00eda molesta.<\/li>\n\n\n\n<li>Los objetos de estilo antiguo ofrecen herencia y m\u00e9todos virtuales, aunque con peque\u00f1as diferencias con las clases modernas. Tenga cuidado\u2009\u2014\u2009suceder\u00e1n cosas malas si intenta usar un objeto sin llamar a su constructor, y el objeto tiene m\u00e9todos virtuales.<\/li>\n<\/ul>\n\n\n\n<p>Se desaconseja utilizar los objetos de estilo antiguo en la mayor\u00eda de los casos. Las clases modernas proporcionan mucha m\u00e1s funcionalidad. Y cuando sea necesario, los registros (incluidos los registros avanzados) se pueden utilizar para el rendimiento. Estos conceptos suelen ser una mejor idea que los objetos de estilo antiguo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Punteros<\/h2>\n\n\n\n<p>Puede crear un puntero a cualquier otro tipo. El puntero para escribir TMyRecord se declara como ^TMyRecord y, por convenci\u00f3n, se llama PMyRecord. Este es un ejemplo tradicional de una lista enlazada de enteros usando registros:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  PMyRecord = ^TMyRecord;\n  TMyRecord = record\n    Value: Integer;\n    Next: PMyRecord;\n  end;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que la definici\u00f3n es recursiva (el tipo PMyRecord se define mediante el tipo TMyRecord, mientras que TMyRecord se define mediante PMyRecord). Se permite definir un tipo puntero a un tipo a\u00fan no definido, siempre que se resuelva dentro del mismo bloque de tipo.<\/p>\n\n\n\n<p>Puede asignar y liberar punteros usando los m\u00e9todos New\/Dispose, o (m\u00e1s bajo nivel, no tipo seguro) m\u00e9todos GetMem\/FreeMem. Elimina la referencia del puntero (para acceder a las cosas se\u00f1aladas por) agrega el operador ^ (por ejemplo, MyInteger := MyPointerToInteger^). Para realizar la operaci\u00f3n inversa, que consiste en obtener un puntero de una variable existente, se antepone el operador @ (por ejemplo, MyPointerToInteger := @MyInteger).<\/p>\n\n\n\n<p>Tambi\u00e9n hay un tipo de puntero sin tipo, similar a void* en lenguajes tipo C. Es completamente inseguro y puede encasillarse en cualquier otro tipo de puntero.<\/p>\n\n\n\n<p>Recuerde que una instancia de clase tambi\u00e9n es, de hecho, un puntero, aunque no requiere ning\u00fan operador ^ o @ para usarlo. Una lista enlazada usando clases es ciertamente posible, ser\u00eda simplemente esto:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyClass = class\n    Value: Integer;\n    Next: TMyClass;\n  end;<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Sobrecarga de operadores<\/h2>\n\n\n\n<p>Puede anular el significado de muchos operadores de idiomas, por ejemplo, para permitir la adici\u00f3n y multiplicaci\u00f3n de sus tipos personalizados. Como esto:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  StrUtils;\n\noperator* (const S: string; const A: Integer): string;\nbegin\n  Result := DupeString(S, A);\nend;\n\nbegin\n  WriteLn('bla' * 10);\nend.<\/pre><\/div>\n\n\n\n<p>Tambi\u00e9n puede anular operadores en clases. Dado que generalmente crea nuevas instancias de sus clases dentro de la funci\u00f3n del operador, la persona que llama debe recordar liberar el resultado.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  TMyClass = class\n    MyInt: Integer;\n  end;\n\noperator* (const C1, C2: TMyClass): TMyClass;\nbegin\n  Result := TMyClass.Create;\n  Result.MyInt := C1.MyInt * C2.MyInt;\nend;\n\nvar\n  C1, C2: TMyClass;\nbegin\n  C1 := TMyClass.Create;\n  try\n    C1.MyInt := 12;\n    C2 := C1 * C1;\n    try\n      WriteLn('12 * 12 = ', C2.MyInt);\n    finally\n      FreeAndNil(C2);\n    end;\n  finally\n    FreeAndNil(C1);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Tambi\u00e9n puede anular operadores en registros. Esto suele ser m\u00e1s f\u00e1cil que sobrecargarlos para las clases, ya que la persona que llama no tiene que lidiar con la gesti\u00f3n de la memoria.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  TMyRecord = record\n    MyInt: Integer;\n  end;\n\noperator* (const C1, C2: TMyRecord): TMyRecord;\nbegin\n  Result.MyInt := C1.MyInt * C2.MyInt;\nend;\n\nvar\n  R1, R2: TMyRecord;\nbegin\n  R1.MyInt := 12;\n  R2 := R1 * R1;\n  WriteLn('12 * 12 = ', R2.MyInt);\nend.<\/pre><\/div>\n\n\n\n<p>Para registros, se recomienda usar {$modeswitch advancedrecords} y anular operadores como operadores de clase dentro del registro. Esto permite utilizar clases gen\u00e9ricas que dependen de la existencia de alg\u00fan operador (como TFPGList, que depende de la disponibilidad del operador de igualdad) con dichos registros. De lo contrario, no se encontrar\u00eda la definici\u00f3n \u00abglobal\u00bb de un operador (no dentro del registro) (porque no est\u00e1 disponible en el c\u00f3digo que implementa TFPGList), y no podr\u00eda especializar una lista como special TFPGList.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$modeswitch advancedrecords}\nuses\n  SysUtils, FGL;\n\ntype\n  TMyRecord = record\n    MyInt: Integer;\n    class operator+ (const C1, C2: TMyRecord): TMyRecord;\n    class operator= (const C1, C2: TMyRecord): boolean;\n  end;\n\nclass operator TMyRecord.+ (const C1, C2: TMyRecord): TMyRecord;\nbegin\n  Result.MyInt := C1.MyInt + C2.MyInt;\nend;\n\nclass operator TMyRecord.= (const C1, C2: TMyRecord): boolean;\nbegin\n  Result := C1.MyInt = C2.MyInt;\nend;\n\ntype\n  TMyRecordList = specialize TFPGList&lt;TMyRecord&gt;;\n\nvar\n  R, ListItem: TMyRecord;\n  L: TMyRecordList;\nbegin\n  L := TMyRecordList.Create;\n  try\n    R.MyInt := 1;   L.Add(R);\n    R.MyInt := 10;  L.Add(R);\n    R.MyInt := 100; L.Add(R);\n\n    R.MyInt := 0;\n    for ListItem in L do\n      R := ListItem + R;\n\n    WriteLn('1 + 10 + 100 = ', R.MyInt);\n  finally\n    FreeAndNil(L);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Funciones varias del lenguaje Continuamos con la introducci\u00f3n al lenguaje Pascal Moderno. Esta entrada es una traducci\u00f3n al espa\u00f1ol, del texto original escrito por Michalis Kamburelis.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,25,26],"tags":[22,23,21],"class_list":["post-327","post","type-post","status-publish","format-standard","hentry","category-lazarus","category-pascal","category-programacion","tag-delphi","tag-lazarus","tag-pascal"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/327","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=327"}],"version-history":[{"count":7,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/327\/revisions"}],"predecessor-version":[{"id":348,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/327\/revisions\/348"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=327"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=327"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=327"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}