2009-03-28 10 views
12

Estoy diseñando un lenguaje, y me pregunto si es razonable hacer que los tipos de referencia no se puedan anular por defecto, y usar "?" para valores nulos y tipos de referencia. ¿Hay algún problema con esto? ¿Qué haría usted en esto:Tipos de referencia no anulables

class Foo { 
    Bar? b; 
    Bar b2; 
    Foo() { 
     b.DoSomething(); //valid, but will cause exception 
     b2.DoSomething(); //? 
    } 
} 
+0

posible duplicado de [La mejor explicación para idiomas sin nulo] (http://stackoverflow.com/questions/3989264/best-explanation-for-languages-without-null) – nawfal

Respuesta

16

Mi filosofía de diseño del lenguaje actual es que la nulabilidad debe ser algo que un programador está obligado a pedir, no por defecto en tipos de referencia (en esto, estoy de acuerdo con Tony Hoare - Google por su reciente charla QCon).

En este ejemplo específico, con el b2 que no se puede anular, ni siquiera pasará controles estáticos: el análisis conservador no puede garantizar que b2 no sea NULO, por lo que el programa no tiene significado semántico.

Mi ethos es bastante simple. Las referencias son un identificador indirecto de algún recurso, que podemos atravesar para obtener acceso a ese recurso. Las referencias anulables son un identificador de indirección a un recurso, o una notificación de que el recurso no está disponible, y nunca se sabe con seguridad qué semántica se está utilizando. Esto le da una multitud de cheques por adelantado (¿es nulo? ¿No? ¡Sí!), O el inevitable NPE (o equivalente). La mayoría de los recursos de programación son, en estos días, no se ve impedido o masivamente recursos asociados a una determinada modelo subyacente finita - referencias nulas son, de manera simplista, uno de ...

  • pereza: "Voy a bụng un nulo en aquí" . Que francamente, no tengo demasiada simpatía con
  • Confusión: "No sé qué poner aquí todavía". Típicamente también un legado de idiomas más antiguos, donde tenía que declarar sus nombres de recursos antes de saber cuáles eran sus recursos.
  • Errores: "Salió mal, aquí hay un NULO". Mejores mecanismos de informe de errores son esenciales en un lenguaje
  • Un hoyo: "Sé que tendré algo pronto, dame un marcador de posición". Esto tiene más mérito, y podemos pensar en formas de combatir esto.

Por supuesto, resolver cada uno de los casos que NULL current atiende con una mejor elección lingüística no es poca cosa, y puede agregar más confusión que ayuda. Siempre podemos ir a recursos inmutables, por lo que NULL en sus únicos estados útiles (error y agujero) no es muy útil. Las técnicas imperativas están aquí para quedarse, y estoy francamente contento, esto hace que la búsqueda de mejores soluciones en este espacio valga la pena.

3

Un par de ejemplos de características similares en otros idiomas:

También hay Nullable<T> (de C#) pero ese no es un buen ejemplo debido al diferente tratamiento de los tipos de referencia vs. valor.

En su ejemplo, puede agregar un operador de envío de mensajes condicional, p.

b?->DoSomething(); 

Para enviar un mensaje a b sólo si es no nulo.

4

Eche un vistazo a la propuesta Elvis operator para Java 7.Esto hace algo similar, ya que encapsula una verificación nula y el envío de métodos en un operador, con un valor de retorno especificado si el objeto es nulo. Por lo tanto:

String s = mayBeNull?.toString() ?: "null"; 

comprueba si la cadena s es nulo, y devuelve la cadena "nula" si es así, y el valor de la cadena si no. Algo para pensar, tal vez.

+3

¿Por qué se llama esto el operador de Elvis? – Zifre

+0

Buena pregunta, y una que no sabía la respuesta. Sin embargo, consulte http://www.infoq.com/articles/groovy-1.5-new re. el operador?:, que está relacionado. Un poco tenue, sin embargo ... –

+0

Solo puedo suponer que es una broma sobre qué hacer si el objeto ha "abandonado el edificio". –

11

Tener tipos de referencia no obligatorios por defecto es la única opción razonable. Estamos plagados de idiomas y tiempos de ejecución que han arruinado esto; deberías hacer lo correcto.

+0

Mire para explicar su posición dogmática. – Kromster

-3

Creo que los valores nulos son buenos: son una clara indicación de que hiciste algo mal. Si no puede inicializar una referencia en algún lugar, recibirá un aviso inmediato.

La alternativa sería que los valores a veces se inicializan a un valor predeterminado. Los errores lógicos son mucho más difíciles de detectar, a menos que ponga la lógica de detección en esos valores predeterminados. Esto sería lo mismo que obtener una excepción de puntero nulo.

+0

A veces es necesario inicializar algo sin saber el valor que eventualmente tendrá. Esto es relativamente raro, sin embargo. Por lo general, la inicialización tiene lugar en la misma línea que la declaración. Además, la propuesta no elimina los valores nulos, solo los hace no nulos por defecto. – kvb

+2

Además, no es cierto que recibirá un aviso inmediato. Obtendrá una excepción tan pronto como intente desreferenciar el valor nulo, pero esa excepción podrá detectarse, y solo lo descubrirá en tiempo de ejecución, no en tiempo de compilación. – kvb

+1

El problema es que no puede obligar a los programadores a inicializar una variable de forma correcta: ¿Cuántas veces ha visto: DataSet ds = new DataSet(); ... ds = ReadDataSet (...); en el código? Si ds no aceptaban nulos, no se detectaría ningún error si se olvidaba la llamada a ReadDataSet(). – Lennaert

9

Esta característica estaba en Spec#. ¡Dejaron de forma predeterminada referencias anulables y se usaron! para indicar no-nulables. Esto fue porque querían compatibilidad con versiones anteriores.

En mi lenguaje de ensueño (del cual probablemente sería el único usuario!) Tomaría la misma decisión que usted, que no admite nulos por defecto.

También haría ilegal el uso de. operador en una referencia anulable (o cualquier otra cosa que lo desreferencia). Cómo los usarías? Tendría que convertirlos primero a no nulables. ¿Cómo harías esto? Probándolos para null.

En Java y C#, la instrucción if solo acepta una expresión de prueba bool. Me extiendo a aceptar el nombre de una variable de referencia anulable:

if (myObj) 
{ 
    // in this scope, myObj is non-nullable, so can be used 
} 

Esta sintaxis especial sería sorprendente que los programadores de C/C++. Prefiero una sintaxis especial como esta para dejar en claro que estamos haciendo un control que modifica el tipo del nombre myObj dentro de la rama de verdad.

me gustaría añadir un poco más de azúcar:

if (SomeMethodReturningANullable() into anotherObj) 
{ 
    // anotherObj is non-nullable, so can be used 
} 

Esto sólo da el nombre anotherObj al resultado de la expresión de la izquierda de la into, por lo que se pueden utilizar en el ámbito donde es válida.

Haría el mismo tipo de cosas para el operador ?:.

string message = GetMessage() into m ? m : "No message available"; 

Nota que string message no es anulable, pero también lo son los dos posibles resultados de la prueba anterior, por lo que la asignación es el valor.

Y entonces tal vez un poco de azúcar para el caso de suponer común de sustituir un valor de nulo:

string message = GetMessage() or "No message available"; 

Obviamente or solamente se aplicaría de forma válida a un tipo anulable en el lado izquierdo, y un no nullable en el lado derecho.

(También me tienen incorporado un concepto de propiedad para los campos de instancia;. El compilador generaría el método IDisposable.Dispose de forma automática, y la sintaxis ~Destructor sería utilizado para aumentar Dispose, exactamente igual que en C++/CLI)

SpeC# tenía otra extensión sintáctica relacionado con los no nullables, debido al problema de asegurar que no nullables habían sido inicializado correctamente durante la construcción:

class SpecSharpExampleClass 
{ 
    private string! _nonNullableExampleField; 

    public SpecSharpExampleClass(string s) 
     : _nonNullableExampleField(s) 
    { 

    } 
} 

en otras palabras, usted tiene que inicializar los campos de la de la misma manera que llamarías a otros constructores con base o this - a menos que, por supuesto, los inicialice directamente junto a la declaración de campo.

+0

en tu primera oración, dijiste "no cumplieron con las referencias nulables", ¿te refieres a las que no admiten nulos? –

+1

@Joan Venge - No. Más adelante en esa misma oración, explico por qué: SpeC# intentó compilar código C# existente correctamente, por lo que se debe suponer que una referencia es anulable a menos que el código indique lo contrario. –

+1

Gracias Daniel. Pensé que SpeC# era lo contrario, ya que pensaban que era mejor, pero entiendo lo que quieres decir ahora. –

-1

Haga que la capacidad de nulos sea una configuración, ejecutable en el código fuente del autor. De esta forma, permitirá que las personas que les gusta los objetos con nulos puedan disfrutarlos de forma predeterminada en su código fuente, al tiempo que permite que aquellos a los que les gustaría que todos sus objetos no sean nulos por defecto tengan exactamente eso. Además, proporcione palabras clave u otras facilidades para marcar explícitamente cuáles de sus declaraciones de objetos y tipos pueden ser anulables y cuáles no, con algo como nullable y not-nullable, para anular los valores predeterminados globales.

Por ejemplo

/// "translation unit 1" 

#set nullable 
{ /// Scope of default override, making all declarations within the scope nullable implicitly 
    Bar bar; /// Can be null 
    non-null Foo foo; /// Overriden, cannot be null 
    nullable FooBar foobar; /// Overriden, can be null, even without the scope definition above 
} 

/// Same style for opposite 

/// ... 

/// Top-bottom, until reset by scoped-setting or simply reset to another value 
#set nullable; 

/// Nullable types implicitly 

#clear nullable; 

/// Can also use '#set nullable = false' or '#set not-nullable = true'. Ugly, but human mind is a very original, mhm, thing. 

Muchas personas argumentan que dar a cada uno lo que quieren es imposible, pero si usted está diseñando un nuevo idioma, probar cosas nuevas. Tony Hoare introdujo el concepto de null en 1965 porque no pudo resistir (sus propias palabras), y estamos pagando por ello desde entonces (también, sus propias palabras, el hombre se arrepiente de ello). El punto es que las personas inteligentes y con experiencia cometen errores que nos cuestan al resto de nosotros, no acepten los consejos de nadie en esta página como si fuera la única verdad, incluida la mía. Evaluar y pensar sobre eso.

He leído muchos comentarios acerca de cómo somos nosotros los pobres programadores inexpertos que realmente no entienden dónde usar realmente null y dónde no, mostrándonos patrones y antipatterns que pretenden evitar que nos peguemos un tiro en el pie. Mientras tanto, millones de programadores aún inexpertos producen más código en los idiomas que permiten null. I puede ser inexperto, pero sé cuáles de mis objetos no se benefician de ser nulo.

+0

¿Por qué el voto a favor? ¿Has visto cómo son los programas grandes con casi cada referencia con el prefijo '@ NonNull'? A veces estoy sorprendido por el estado de la informática, pero ¿qué más hay de nuevo? Merecemos los programas que tenemos :-) – amn

Cuestiones relacionadas