¿Es la información oculta más que una convención?


20

En Java, C # y muchos otros lenguajes fuertemente tipados, estáticamente verificados, estamos acostumbrados a escribir código como este:

public void m1() { ... }
protected void m2() { ... }
private void m2() { ... }
void m2() { ... }

Algunos idiomas controlados dinámicamente no proporcionan palabras clave para expresar el nivel de "privacidad" de un miembro de la clase en particular y se basan en convenciones de codificación. Python, por ejemplo, antepone a miembros privados con un guión bajo:

_m(self): pass

Se puede argumentar que proporcionar tales palabras clave en idiomas dinámicamente controlados agregaría poco uso ya que solo se verifica en tiempo de ejecución.

Sin embargo, tampoco puedo encontrar una buena razón para proporcionar estas palabras clave en idiomas controlados estáticamente. Encuentro el requisito de llenar mi código con palabras clave bastante detalladas, como protectedmolesto y molesto. Hasta ahora, no he estado en una situación en la que un error del compilador causado por estas palabras clave me hubiera salvado de un error. Muy al contrario, he estado en situaciones en las que un lugar equivocado protectedme impidió usar una biblioteca.

Con esto en mente, mi pregunta es:

¿La información oculta es más que una convención entre programadores utilizada para definir qué es parte de la interfaz oficial de una clase?

¿Se puede usar para asegurar que el estado secreto de una clase no sea atacado? ¿Puede la reflexión anular este mecanismo? ¿Qué haría que valiera la pena para el compilador forzar el ocultamiento de información?


10
Lo sentimos, Eric Lippert está de vacaciones :)
Benjol 05 de

Tu pregunta es un poco difícil de entender. ¿Básicamente solo preguntas si alguien puede acceder a un miembro privado desde afuera?
Morgan Herlocker


@ironcode: puedo decir que de alguna manera no me expreso lo suficientemente claro a partir de algunas de las respuestas. ¿Puedes decir qué específicamente hace que sea difícil de entender? Trataré de aclararlo.
blubb

2
"No tiene sentido proporcionar información en tiempo de compilación y luego solo verificarla en tiempo de ejecución" - ¿en serio? Es mejor decirle eso a Microsoft porque eso es en lo que se basa una parte significativa del marco .NET actual: la inclusión selectiva o la exclusión voluntaria de la escritura estática. Sin embargo, no creo que esto sea realmente lo que quieres decir; la pregunta habla repetidamente sobre la verificación "estática" frente a la "dinámica", pero esas son características del sistema de tipos; lo que realmente está en cuestión aquí es en tiempo de compilación vs. tiempo de ejecución vinculante .
Aaronaught

Respuestas:


4

Estoy estudiando para la certificación de Java y un montón de eso se refiere a cómo administrar modificadores de acceso. Y tienen sentido y deben usarse correctamente.

Trabajé con Python y, durante mi viaje de aprendizaje, escuché que en Python, la convención está ahí porque las personas que trabajan con ella deben saber qué significa y cómo aplicarla. Dicho esto, en _m(self): passel guión bajo me alertaría de no perder el tiempo con ese campo. ¿Pero todos seguirán esa convención? Trabajo con javascript y debo decir que no . A veces necesito verificar un problema y la razón era que la persona estaba haciendo algo que no debía hacer ...

lea esta discusión sobre el guión bajo de Python

¿La información oculta es más que una convención entre programadores utilizada para definir qué es parte de la interfaz oficial de una clase?

Por lo que dije, sí.

¿Se puede usar para asegurar que el estado secreto de una clase no sea atacado? ¿Puede la reflexión anular este mecanismo? ¿Hay otras ventajas proporcionadas por un mecanismo más formal impuesto por el compilador?

Sí, se puede usar para asegurar el estado secreto de una clase y no solo se debe usar para eso, sino para evitar que los usuarios jueguen con el estado de los objetos para cambiar sus comportamientos a algo que creen que debería ser la forma en que el objeto debería estado trabajando. Usted, como desarrollador, debe planificarlo y pensarlo y diseñar su clase de una manera que tenga sentido, de manera que su comportamiento no sea alterado. Y el compilador, como buen amigo, lo ayudará a mantener el código de la forma en que lo diseñó para hacer cumplir las políticas de acceso.

EDITADO Sí, la reflexión puede, verifique los comentarios

La última pregunta es interesante y estoy dispuesto a leer las respuestas al respecto.


3
La reflexión generalmente puede pasar por alto la protección de acceso. Para Java y C #, ambos pueden acceder a datos privados.
Mark H

¡Gracias! Las respuestas aquí: stackoverflow.com/questions/1565734/… ¡ explícalo!
wleao

1
La cultura Javascript es muy diferente de la cultura python. Python tiene pep-08 y casi todos los desarrolladores de python siguen estas convenciones. Las violaciones de PEP-08 a menudo se consideran un error. Así que creo que la experiencia de javascript / php / perl / ruby ​​se traduce muy poco en la experiencia de python en este aspecto: _private funciona muy bien en python.
Mike Korobov

1
En algunos (pero no en todos) los lenguajes de programación, la ocultación de información se puede utilizar para proteger contra el código hostil. La ocultación de información no se puede utilizar para proteger contra usuarios hostiles.
Brian

2
@Mike si las violaciones de PEP-08 a menudo se "consideran como un error", y ningún desarrollador de Python soñaría con no seguir las convenciones, ¡entonces es posible que el lenguaje las haga cumplir! ¿Por qué el trabajo servil cuando el idioma puede hacerlo automáticamente?
Andres F.

27

El especificador de acceso "privado" no se trata del error del compilador que genera la primera vez que lo ve. En realidad, se trata de evitar que acceda a algo que aún está sujeto a cambios cuando cambia la implementación de la clase que tiene al miembro privado.

En otras palabras, no permitirle usarlo cuando todavía está funcionando le impide seguir usándolo accidentalmente cuando ya no funciona.

Como Delnan comentó a continuación, la convención de prefijo desalienta el uso accidental de miembros que están sujetos a cambios siempre que la convención se siga y se entienda correctamente. Para un usuario malintencionado (o ignorante) no hace nada para evitar que acceda a ese miembro con todas las posibles consecuencias. En idiomas con soporte incorporado para especificadores de acceso, esto no ocurre por ignorancia (error del compilador), y se destaca como un pulgar doloroso cuando es malicioso (construcciones extrañas para llegar al miembro privado).

El especificador de acceso "protegido" es una historia diferente. No piense en esto simplemente como "no del todo público" o "muy parecido a privado". "Protegido" significa que probablemente querrá usar esa funcionalidad cuando derive de la clase que contiene el miembro protegido. Los miembros protegidos son parte de la "interfaz de extensión" que usará para agregar funcionalidad a las clases existentes sin cambiar esas clases existentes.

Entonces, resumen breve:

  • public: Usar de forma segura en instancias de la clase, el propósito de la clase no cambiará.
  • Protegido: para usarse al extender (derivado de) la clase; puede cambiar si la implementación tiene que cambiar drásticamente.
  • privado: no tocar! Puede cambiar a voluntad para proporcionar una mejor implementación de las interfaces esperadas.

3
Más importante aún, cualquier (fácilmente reconocible, como es el caso, por ejemplo, con guiones bajos) no se aplica la convención para "detalles de implementación, sujetos a cambios" también evita el uso por parte de un miembro privado. En Python, por ejemplo, la única vez que un programador cuerdo escribe código usando un miembro privado desde el exterior (e incluso entonces está mal visto) es cuando es casi inevitable, sabe exactamente lo que hace y acepta la posible ruptura en futuras versiones. . Es decir, una situación en la que, por ejemplo, los programadores de Java utilizarían la reflexión.

3
@Simon Stelling - no, estoy diciendo que el implementador original de la clase que hizo algo privado te está diciendo "no uses esto, cualquier comportamiento aquí puede cambiar en el futuro". Por ejemplo, una variable miembro privada de una clase que primero contiene una distancia entre dos puntos puede contener luego la distancia entre dos puntos al cuadrado por razones de rendimiento. Cualquier cosa que hubiera dependido del viejo comportamiento se rompería en silencio.
Joris Timmermans

1
@MadKeithV: Entonces, ¿cómo es una palabra clave de nivel de lenguaje que dice "no tocar porque ..." diferente de una convención que significa lo mismo? Solo el compilador lo aplica, pero luego volvemos a la vieja discusión estática vs. dinámica.

77
@Simon Stelling (y Delnan): para mí eso es como preguntar "en qué se diferencia un limitador del motor de una señal de límite de velocidad".
Joris Timmermans

1
Soy consciente de la diferencia y nunca dije que no estaba allí. Simplemente encuentro que su respuesta y la mayoría de sus comentarios de seguimiento simplemente describen los tipos de anotaciones a los miembros y los métodos que se pueden hacer con convenciones o palabras clave a nivel de idioma y dejan la diferencia real (presencia de aplicación de nivel de idioma) inferido por el lector.

11

Si está escribiendo código que será consumido por otra persona, la ocultación de información puede proporcionar una interfaz mucho más fácil de entender. "Alguien más" podría ser otro desarrollador en su equipo, desarrolladores que consumen una API que usted escribió comercialmente, o incluso su futuro yo que "simplemente no puede recordar cómo funciona la cosa". Es mucho más fácil trabajar con una clase que tiene solo 4 métodos disponibles que uno que tiene 40.


2
Estoy totalmente de acuerdo, pero esto no responde a mi pregunta. Si uso _membero private memberen mi clase es insignificante, siempre y cuando el otro programador entienda que solo debe mirar a publiclos miembros no prefijados.
blubb

66
Sí, pero la documentación pública de una clase escrita en un lenguaje dinámico tampoco arroja esas 36 partes privadas (al menos no de manera predeterminada).

3
@Simon La afirmación de que es "solo una convención" es engañosa, ya que tiene beneficios reales. "Solo una convención" es algo así como llaves en la siguiente línea. Una convención con beneficios es algo así como el uso de nombres significativos, lo que yo diría que es totalmente diferente. ¿Establecer algo en privado impide que alguien te vea "métodos secretos"? No, no si están determinados.
Morgan Herlocker

1
@ Simon- también, solo exponer métodos que son seguros de usar aumenta la posibilidad de que el usuario no rompa algo cuando intente usar la clase. Podría haber métodos fácilmente que podrían bloquear un servidor web si se llama mil veces. No desea que los consumidores de su API puedan hacerlo. La abstracción es más que una simple convención.
Morgan Herlocker

4

Sugeriría que para el fondo, comience leyendo sobre invariantes de clase .

Una invariante es, para resumir una historia larga, una suposición sobre el estado de una clase que se supone que debe mantenerse durante toda la vida de una clase.

Usemos un ejemplo de C # realmente simple:

public class EmailAlert
{
    private readonly List<string> addresses = new List<string>();

    public void AddRecipient(string address)
    {
        if (!string.IsNullOrEmpty(address))
            addresses.Add(address);
    }

    public void Send(string message)
    {
        foreach (string address in addresses)
            SendTo(address, message);
    }

    // Details of SendTo not shown
}

¿Que está pasando aqui?

  • El miembro addressesse inicializa en la construcción de la clase.
  • Es privado, por lo que nada del exterior puede tocarlo.
  • También lo hemos hecho readonly, por lo que nada desde el interior puede tocarlo después de la construcción (esto no siempre es correcto / necesario, pero es útil aquí).
  • Por lo tanto, el Sendmétodo puede hacer una suposición que addressesnunca será null. No tiene que realizar esa verificación porque no hay forma de que se pueda cambiar el valor.

Si se permitiera a otras clases escribir en el addressescampo (es decir, si lo fuera public), esta suposición ya no sería válida. Cualquier otro método de la clase que dependa de ese campo tendría que comenzar a hacer comprobaciones nulas explícitas o arriesgarse a bloquear el programa.

Entonces sí, es mucho más que una "convención"; Todos los modificadores de acceso en los miembros de la clase forman colectivamente un conjunto de suposiciones sobre cuándo y cómo se puede cambiar ese estado. Esos supuestos se incorporan posteriormente a miembros y clases dependientes e interdependientes para que los programadores no tengan que razonar sobre el estado completo del programa al mismo tiempo. La capacidad de hacer suposiciones es un elemento crítico de la gestión de la complejidad en el software.

A estas otras preguntas:

¿Se puede usar para asegurar que el estado secreto de una clase no sea atacado?

Si y no. El código de seguridad, como la mayoría de los códigos, dependerá de ciertos invariantes. Los modificadores de acceso son ciertamente útiles como señales para las personas que llaman de confianza que se supone que no deben molestar. El código malicioso no va a importar, pero el código malicioso tampoco tiene que pasar por el compilador.

¿Puede la reflexión anular este mecanismo?

Por supuesto que puede. Pero la reflexión requiere que el código de llamada tenga ese nivel de privilegio / confianza. Si está ejecutando código malicioso con plena confianza y / o privilegios administrativos, entonces ya ha perdido esa batalla.

¿Qué haría que valiera la pena para el compilador forzar el ocultamiento de información?

El compilador ya lo hace cumplir. Lo mismo ocurre con el tiempo de ejecución en .NET, Java y otros entornos similares: el código de operación utilizado para llamar a un método no tendrá éxito si el método es privado. Las únicas formas de evitar esa restricción requieren un código confiable / elevado, y el código elevado siempre podría escribir directamente en la memoria del programa. Se aplica tanto como se puede aplicar sin requerir un sistema operativo personalizado.


1
@ Simon: Necesitamos aclarar la "ignorancia" aquí. Prefijar un método con _establece el contrato, pero no lo impone. Eso puede hacer que sea difícil ignorar el contrato, pero no dificulta la ruptura del contrato, especialmente cuando se compara con métodos tediosos y a menudo restrictivos como Reflection. Una convención dice: "no deberías romper esto". Un modificador de acceso dice: "no puedes romper esto". Estoy no intento decir que un método es mejor que el otro - ambos están bien dependiendo de su filosofía, pero son sin embargo muy diferentes enfoques.
Aaronaught

2
¿Qué tal una analogía? A private/ protectedmodificador de acceso es como un condón. No tiene que usar uno, pero si no lo va a hacer, será mejor que esté seguro de su momento y su (s) pareja (s). No evitará un acto malicioso, y puede que ni siquiera funcione cada vez, pero definitivamente reducirá los riesgos del descuido y lo hará de manera mucho más efectiva que decir "por favor, tenga cuidado". Ah, y si tienes uno, pero no lo uses, entonces no esperes ninguna simpatía de mi parte.
Aaronaught

3

Ocultar información es mucho más que una simple convención; tratar de evitarlo en realidad puede romper la funcionalidad de la clase en muchos casos. Por ejemplo, es una práctica bastante común almacenar un valor en una privatevariable, exponerlo usando una propiedad protectedo publicdel mismo tiempo, y en el captador, verificar si es nulo y hacer cualquier inicialización que sea necesaria (es decir, carga diferida). O almacene algo en una privatevariable, exponga usando una propiedad y, en el setter, verifique si el valor cambió y se disparó PropertyChanging/ PropertyChangedeventos. Pero sin ver la implementación interna, nunca sabrías todo lo que sucede detrás de escena.


3

La ocultación de información evolucionó a partir de una filosofía de diseño de arriba hacia abajo. Python ha sido llamado un lenguaje ascendente .

La ocultación de información se aplica bien a nivel de clase en Java, C ++ y C #, por lo que no es realmente una convención a este nivel. Es muy fácil convertir una clase en un "recuadro negro", con interfaces públicas y detalles ocultos (privados).

Como señaló, en Python corresponde a los programadores seguir la convención de no usar lo que está destinado a estar oculto, ya que todo es visible.

Incluso con Java, C ++ o C #, en algún momento la ocultación de información se convierte en una convención. No hay controles de acceso en los niveles más altos de abstracción involucrados en arquitecturas de software más complejas. Por ejemplo, en Java puede encontrar el uso de ".internal". nombres de paquetes Esto es puramente una convención de nomenclatura porque no es fácil hacer cumplir este tipo de ocultación de información solo a través de la accesibilidad del paquete.

Un lenguaje que se esfuerza por definir el acceso formalmente es Eiffel. Este artículo señala algunas otras debilidades que ocultan información de lenguajes como Java.

Antecedentes: David Parnas propuso el ocultamiento de información en 1971 . Señala en ese artículo que el uso de información sobre otros módulos puede "aumentar desastrosamente la conectividad de la estructura del sistema". Según esta idea, la falta de ocultación de información puede conducir a sistemas estrechamente acoplados que son difíciles de mantener. Él continúa con:

Deseamos que los diseñadores determinen la estructura del sistema explícitamente antes de que comience la programación, en lugar de inadvertidamente por el uso de información por parte de un programador.


1
+1 para la cita "uso de información por parte del programador", eso es exactamente (aunque tiene una coma adicional al final).
jmoreno

2

Ruby y PHP lo tienen y lo hacen cumplir en tiempo de ejecución.

El punto de ocultar información es en realidad mostrar información. Al "ocultar" los detalles internos, el propósito se hace evidente desde una perspectiva externa. Hay idiomas que abarcan esto. En Java, el acceso predeterminado es el paquete interno, en haXe a protegido. Usted los declara explícitamente públicos para exponerlos.

El objetivo de esto es hacer que sus clases sean fáciles de usar al exponer solo una interfaz altamente coherente. Desea que el resto esté protegido, para que ningún tipo inteligente venga y se meta con su estado interno para engañar a su clase para que haga lo que quiere.

Además, cuando los modificadores de acceso se aplican en tiempo de ejecución, puede usarlos para aplicar un cierto nivel de seguridad, pero no creo que esta sea una solución particularmente buena.


1
Si su biblioteca se está utilizando en la misma compañía en la que está trabajando, le importará ... Si bloquea su aplicación, tendrá dificultades para solucionarlo.
wleao

1
¿Por qué pretender usar un cinturón de seguridad cuando podría usar uno? Reformularía la pregunta y preguntaría, ¿hay alguna razón para que un compilador no la aplique, si toda la información está disponible? No debes esperar hasta tener un choque para averiguar si valía la pena usar ese cinturón de seguridad.
Mark H

1
@Simon: por qué saturar una interfaz con cosas que no quieres que la gente use. Odio que C ++ requiera que cada miembro esté presente en la definición de clase en un archivo de encabezado (entiendo por qué). Las interfaces son para otras personas y no deben estar llenas de cosas que no pueden usar.
phkahler

1
@phkahler: pydocelimina _prefixedMembersde la interfaz. Las interfaces desordenadas no tienen nada que ver con la elección de una palabra clave verificada por el compilador.
blubb

2

Los modificadores de acceso definitivamente pueden hacer algo que la convención no puede hacer.

Por ejemplo, en Java no puede acceder a un miembro / campo privado a menos que use la reflexión.

Por lo tanto, si escribo la interfaz para un complemento y denego correctamente los derechos para modificar campos privados a través de la reflexión (y para configurar el administrador de seguridad :)), puedo enviar algunos objetos a funciones implementadas por cualquier persona y saber que no puede acceder a sus campos privados.

Por supuesto, puede haber algunos errores de seguridad que le permitirían superar esto, pero esto no es filosóficamente importante (pero en la práctica definitivamente lo es).

Si el usuario ejecuta mi interfaz en su entorno, tiene el control y, por lo tanto, puede eludir los modificadores de acceso.


2

No he estado en una situación en la que un error del compilador causado por estas palabras clave me hubiera salvado de un error.

No es tanto para salvar a los autores de aplicaciones de los errores como para permitir que los autores de la biblioteca decidan qué partes de su implementación se comprometen a mantener.

Si tengo una biblioteca

class C {
  public void foo() { ... }

  private void fooHelper() { /* lots of complex code */ }
}

Es posible que desee reemplazar foola implementación y posiblemente cambiar fooHelperde manera radical. Si un grupo de personas ha decidido usarlo a fooHelperpesar de todas las advertencias en mi documentación, es posible que no pueda hacerlo.

privatepermite a los autores de bibliotecas dividir las bibliotecas en métodos de tamaño manejable (y privateclases auxiliares) sin temor a que se vean obligados a mantener esos detalles internos durante años.


¿Qué haría que valiera la pena para el compilador forzar el ocultamiento de información?

En una nota al margen, en Java privateno se aplica por el compilador, sino por el verificador de bytecode de Java .


¿Puede la reflexión anular este mecanismo? ¿Qué haría que valiera la pena para el compilador forzar el ocultamiento de información?

En Java, no solo la reflexión puede anular este mecanismo. Hay dos tipos de privateen Java. El tipo de privateeso evita que una clase externa acceda a los privatemiembros de otra clase externa que es verificada por el verificador de bytecode, pero también privatees utilizada por una clase interna a través de un método de acceso sintético privado de paquete como en

 public class C {
   private int i = 42;

   public class B {
     public void incr() { ++i; }
   }
 }

Como la clase B(realmente llamada C$B) usa i, el compilador crea un método Bde acceso sintético que permite acceder C.ide una manera que supera el verificador de bytecode. Desafortunadamente, dado ClassLoaderque le permite crear una clase a partir de una byte[], es bastante sencillo llegar a las partes privadas que se Chan expuesto a las clases internas creando una nueva clase en Cel paquete que es posible si Cel jar no se ha sellado.

La privateaplicación adecuada requiere coordinación entre los cargadores de clases, el verificador de bytecode y la política de seguridad que puede evitar el acceso reflexivo a los privados.


¿Se puede usar para asegurar que el estado secreto de una clase no sea atacado?

Si. La "descomposición segura" es posible cuando los programadores pueden colaborar mientras cada uno preserva las propiedades de seguridad de sus módulos. No tengo que confiar en el autor de otro módulo de código para no violar las propiedades de seguridad de mi módulo.

Los lenguajes de Capacidades de Objetos como Joe-E usan la ocultación de información y otros medios para hacer posible la descomposición segura:

Joe-E es un subconjunto del lenguaje de programación Java diseñado para admitir una programación segura de acuerdo con la disciplina de capacidad de objeto. Joe-E está destinado a facilitar la construcción de sistemas seguros, así como a facilitar las revisiones de seguridad de los sistemas construidos en Joe-E.

El documento vinculado desde esa página ofrece un ejemplo de cómo la privateaplicación hace posible la descomposición segura.

Proporcionando encapsulación segura.

Figura 1. Una instalación de registro de solo agregar.

public final class Log {
  private final StringBuilder content;
  public Log() {
    content = new StringBuilder();
  }
  public void write(String s) {
    content.append(s);
  }
}

Considere la figura 1, que ilustra cómo se podría construir una instalación de registro de solo agregar. Siempre que el resto del programa esté escrito en Joe-E, un revisor de código puede estar seguro de que las entradas de registro solo se pueden agregar y no se pueden modificar o eliminar. Esta revisión es práctica porque solo requiere la inspección de la Log clase y no requiere la revisión de ningún otro código. En consecuencia, verificar esta propiedad solo requiere un razonamiento local sobre el código de registro.


1

La ocultación de información es una de las principales preocupaciones del buen diseño de software. Echa un vistazo a cualquiera de los documentos de Dave Parnas de finales de los 70. Básicamente, si no puede garantizar que el estado interno de su módulo sea consistente, no puede garantizar nada sobre su comportamiento. Y la única forma en que puede garantizar su estado interno es mantenerlo privado y solo permitir que se modifique por los medios que usted proporcione.


1

Al hacer que la protección sea parte del lenguaje, obtienes algo: seguridad razonable.

Si hago que una variable sea privada, tengo la seguridad razonable de que solo será tocada por el código dentro de esa clase o declarada explícitamente como amigos de esa clase. El alcance del código que podría tocar razonablemente ese valor es limitado y está explícitamente definido.

¿Ahora hay formas de evitar la protección sintáctica? Absolutamente; la mayoría de los idiomas los tienen. En C ++, siempre puede convertir la clase a otro tipo y pinchar en sus bits. En Java y C #, puede reflejarse en él. Etcétera.

Sin embargo, hacer esto es difícil . Es obvio que estás haciendo algo que no deberías estar haciendo. No puede hacerlo por accidente (fuera de las escrituras salvajes en C ++). Debes pensar voluntariamente: "Voy a tocar algo que mi compilador me dijo que no hiciera". Debes voluntariamente hacer algo irracional .

Sin protección sintáctica, un programador puede arruinar accidentalmente las cosas. Tienes que enseñarle al usuario una convención, y ellos deben seguir esa convención cada vez . Si no lo hacen, el mundo se vuelve muy inseguro.

Sin protección sintáctica, la responsabilidad recae en las personas equivocadas: las muchas personas que usan la clase. Deben seguir la convención o se producirá una maldad no especificada. Rasca eso: puede ocurrir una maldad no especificada .

No hay nada peor que una API donde, si haces lo incorrecto, todo podría funcionar de todos modos. Eso proporciona una falsa seguridad al usuario de que ha hecho lo correcto, que todo está bien, etc.

¿Y los nuevos usuarios de ese idioma? No solo tienen que aprender y seguir la sintaxis real (aplicada por el compilador), ahora deben seguir esta convención (aplicada por sus pares en el mejor de los casos). Y si no lo hacen, entonces nada malo puede suceder. ¿Qué sucede si un programador no entiende por qué existe la convención? ¿Qué sucede cuando él dice "atorníllelo" y solo golpea tus partes privadas? ¿Y qué piensa él si todo sigue funcionando?

Él piensa que la convención es estúpida. Y no lo seguirá nunca más. Y les dirá a todos sus amigos que no se molesten también.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.