2010-09-19 11 views
5

Uno de mis errores más comunes es que nunca puedo recordar si algo es un método o una propiedad, por lo que estoy constantemente agregando o quitando paréntesis.¿Por qué java/javascript/python fuerza el uso de() después de un nombre de método, incluso si no toma argumentos?

Así que me preguntaba si había una buena lógica detrás de hacer la diferencia entre llamar a las propiedades de un objeto y los métodos explícitos.

Obviamente, le permite tener propiedades y métodos que comparten el mismo nombre, pero no creo que se acerca mucho.

El único gran beneficio que se me ocurre es la legibilidad. A veces es posible que desee saber si algo es un método o una propiedad mientras mira el código, pero tengo problemas para encontrar ejemplos específicos cuando sería realmente útil. Pero soy un n00b, así que probablemente aún no me he encontrado con una situación así. Apreciaría ejemplos de tal situación.

Además, ¿hay otros idiomas donde la diferencia no es explícita?

De todas formas, si se pudiera responder, que me ayudará a ser menos molesto cada vez que hago este error^- ^.

ACTUALIZACIÓN: Gracias a todos por las respuestas impresionantes hasta ahora! Solo tengo una semana de js y 1 día de python, así que no tenía idea de que pudieras hacer referencia a las funciones sin llamarlas. Eso es genial. Tengo un poco más de experiencia con Java, así que de allí vengo en su mayoría ... ¿alguien puede presentar un argumento igualmente convincente para que ese sea el caso en Java, donde no se puede hacer referencia a las funciones? Además de ser un lenguaje muy explícito, con todos los beneficios que conlleva :).

+0

no es tanto que requiera '()', ya que le está diciendo al compilador y a los futuros televidentes de su código, "Esta es una función que no requiere parámetros". Explícito siempre es mejor que implícito. – orokusaki

Respuesta

1

Normalmente, las propiedades son accesadores y los métodos realizan algún tipo de acción. Partiendo de esta suposición, es barato usar una propiedad, es costoso usar un método.

Foo.Bar, por ejemplo, indicaría a mí que sería devolver un valor, como una cuerda, sin un montón de gastos generales.

Foo.Bar() (o más probablemente, Foo.GetBar()), por otro lado, implica la necesidad de recuperar el valor de "Barra", tal vez de una base de datos.

Las propiedades y los métodos tienen diferentes propósitos y diferentes implicaciones, por lo que también deben diferenciarse en el código.

Por cierto, en todos los idiomas que conozco la diferencia en la sintaxis es explícita, pero detrás de las escenas propiedades son tratados a menudo como llamadas a métodos simplemente especiales.

+1

Acepto que los accesos de propiedad deben ser baratos, pero no estoy de acuerdo con la otra mitad; muchas funciones son muy baratas para llamar. –

+0

No niego eso, pero esta es una discusión de comparaciones de * el mismo * método/propiedad con * el mismo * nombre - ¿cuál esperaría tener más sobrecarga? – jvenema

+0

Espero que un getter (es decir, GetX) tenga una implementación bastante barata. No veo que implique la necesidad de recuperar el valor. La mayoría de los getters que he visto simplemente devuelven un atributo. –

3

creo que su respuesta es sí mismo:

Uno de mis errores más comunes es que nunca puedo recordar si algo es un método o una propiedad, así que estoy constantemente añadiendo o quitando paréntesis.

considerar lo siguiente:

if (colorOfTheSky == 'blue')

vs:

if (colorOfTheSky() == 'blue')

Podemos saber con sólo mirar que las primeras comprobaciones para una variable llamada colorOfTheSky, y queremos saber si su valor es blue. En el segundo, sabemos que colorOfTheSky() llama a una función (método) y queremos saber si su valor de retorno es blue.

Si no tuviéramos esta distinción, sería extremadamente ambiguo en situaciones como esta.

Para responder a su última pregunta, no conozco ningún idioma que no tenga esta distinción.

Además, probablemente tenga un problema de diseño si no puede distinguir entre sus métodos y sus propiedades; como señala otra respuesta, los métodos y las propiedades tienen diferentes roles para jugar. Además, es una buena práctica que los nombres de sus métodos sean acciones, p. getPageTitle, getUserId, etc., y para que sus propiedades sean sustantivos, por ejemplo, pageTitle, userId. Debes poder descifrarlos fácilmente en tu código tanto para ti como para cualquiera que venga después y lea tu código.

+0

Esto es incorrecto en Python para nombres de métodos (nombres de funciones no desnudos); 'foo.colorOfTheSky' es una función invocada si' colorOfTheSky' es una propiedad. No estoy loco por esto en general, pero es útil si necesita proporcionar un particular en Terface que expone atributos de clase pero necesita implementarlo con llamadas de función detrás de escena. –

+0

@Glenn: No sabía eso; Gracias por la info. –

5

Al menos en JS, es porque se pueden pasar funciones.

var func = new Function(); 

luego se puede así que algo como

var f = func 
f() 

por lo que 'f' y 'func' son referencias a la función, y f() o func() es la invocación de la función.

que no es el mismo que

var val = f(); 

que asigna el resultado de la invocación a una var.

Para Java, no se pueden pasar funciones, al menos como se puede en JS, por lo que no hay ninguna razón para que el lenguaje requiera a() invocar un método. Pero es lo que es.

No puedo hablar para pitón.

Pero el punto principal es que los diferentes idiomas pueden tener razones por las cuales la sintaxis puede ser necesaria, y en ocasiones la sintaxis es solo la sintaxis.

13

Todos los idiomas modernos requieren esto porque referencia a una función y llamar una función son acciones separadas.

Por ejemplo,

def func(): 
    print "hello" 
    return 10 
a = func 
a() 

Claramente, a = func y a = func() tienen significados muy diferentes.

Ruby: el lenguaje más probable en el que estás pensando, por el contrario, no requiere los paréntesis; puede hacer esto porque no admite tomar referencias a funciones.

+3

La razón por la cual Ruby no admite tomar referencias a funciones es porque es un lenguaje orientado a objetos y, por lo tanto, no * tiene * funciones. Sin embargo, tiene * métodos * y * admite * admitir referencias a métodos. –

+15

Siempre puede contar con los Rubyites que salen de los arbustos en cualquier señal de una crítica de su idioma, por lo general con un intento repetido de redefinir la palabra "función". –

+1

@Juan Pablo Califano: la característica principal de una función es que no puede tener ningún efecto secundario. Los métodos de Ruby * pueden * tener efectos secundarios, por lo tanto no pueden ser funciones. –

8

En idiomas como Python y JavaScript, las funciones son objetos de primera clase. Esto significa que puede pasar funciones, al igual que puede pasar cualquier otro valor. Los paréntesis después del nombre de la función (el () en myfunc()) en realidad constituyen un operador, al igual que + o . En lugar de significar "agregar este número a otro número" (en el caso de +), () significa "ejecutar la función anterior". Esto es necesario porque es posible usar una función sin ejecutarla. Por ejemplo, puede que desee para compararla con otra función utilizando ==, o puede que desee pasar en otra función, como en este ejemplo de JavaScript:

function alertSomething(message) { 
    alert(message); 
} 

function myOtherFunction(someFunction, someArg) { 
    someFunction(someArg); 
} 

// here we are using the alertSomething function without calling it directly 
myOtherFunction(alertSomething, "Hello, araneae!"); 

En resumen: es importante ser capaz de se refieren a una función sin llamarla; esta es la razón por la cual la distinción es necesaria.

+0

Oh, vaya, ¡no sabía que pudieras hacer eso! Ese es un gran ejemplo. – araneae

2

Porque hacer una referencia y llamar a un método son dos cosas diferentes. Considere X.method siendo el método de class X y x una instancia de X, por lo que x.method == 'blue' nunca podrá ser cierto porque los métodos no son cadenas.

Puede probar esto: imprimir un método de un objeto:


>>> class X(object): 
... def a(self): 
...  print 'a' 
... 
>>> x=X() 
>>> print x.a 
<bound method X.a of <__main__.X object at 0x0235A910>> 

3

Si usted está teniendo problemas, distinguiendo entre sus propiedades y métodos, es probable que no nombrarlos muy bien.

En general, sus métodos deben tener un verbo en ellos: es decir, escribir, imprimir, eco, abrir, cerrar, obtener, establecer y nombres de propiedad deben ser sustantivos o adjetivos: nombre, color, relleno, cargado.

Es muy importante usar métodos y nombres de propiedades con sentido, sin eso, encontrará que tendrá dificultades para leer su propio código.

+0

En realidad, generalmente es un problema con cosas que no mencioné. Por ejemplo, para usar un objeto TreeWalker, lastChild() es un método, pero currentNode es una propiedad. Supongo que tiene sentido que se guarde la posición actual, pero no es obvio que el último hijo no lo esté. ¿Y qué hay de obj.length u obj.length()? En JS, la longitud es una propiedad de una cadena pero en java es un método ... quizás DEBERÍA ser getLength() pero no lo es: P – araneae

+0

Si se trata de un método, implica que el procesador hace un cálculo para devolver una valor, si es una propiedad, entonces es simplemente un valor que se recupera de la RAM. Por ejemplo, currentNode se almacena y recupera, mientras que para que lastChild sea devuelto, el procesador primero debe determinar el número de elementos en el nodo, luego devolver el último valor, como tal, el valor de lastChild no se almacena en la memoria, pero se calcula cuando necesario. Igual que obj.length [()], javascript almacena el valor, mientras que java lo calcula. –

+0

Derecha. Entiendo la diferencia, solo estaba señalando que en esos dos ejemplos el nombre del método no tenía verbos en ellos (lastChild() y length()) y que era el código que no escribí yo mismo. – araneae

2

En Java, puedo pensar en dos razones por las que () se requiere:

1) de Java tenían un objetivo específico de diseño para tener una "C/C++ como" sintaxis, para hacer más fácil para C y C++ programadores para aprender el idioma. Tanto C como C++ requieren los paréntesis.

2) La sintaxis de Java requiere específicamente que los paréntesis eliminen la ambigüedad de una referencia a un atributo o local de una llamada a un método. Esto se debe a que los nombres de los métodos y los nombres de los atributos/locales se declaran en diferentes espacios de nombres. Así que la siguiente es legal de Java:

public class SomeClass { 
    private int name; 
    private int name() { ... } 

    ... 

    int norm = name; // this one 
} 

Si el () no era necesario para una llamada de método, el compilador no sería capaz de decir si la instrucción con etiqueta ("este") se asigna el valor de la name atributo o el resultado de llamar al método name().

+0

Sospecho que # 1 es la razón por la cual Java es así; es un lenguaje muy explícito. # 2 aborda el hecho de que los métodos y las variables pueden tener el mismo nombre en Java. El efecto inconsecuente (imo) de eliminar() sería que simplemente tendría que tener nombres únicos para métodos y campos.Estoy buscando algo más catastrófico; Ciertamente, los espacios de nombres en Java son un poco complicados, con herencia y todo; tal vez podría haber consecuencias involuntarias (o al menos difíciles para el compilador) con eso? – araneae

+0

@araneae - bien podría haber otras razones. Pero la pregunta es discutible. Java es lo que es Java. Algo tan fundamental como esto no va a cambiar. –

2

La diferencia no siempre es explícita en VBA. Esta es una llamada a un Sub (es decirun método sin valor de retorno), que no toma ningún parámetro (todos los ejemplos son de Excel):

Worksheets("Sheet1").UsedRange.Columns.AutoFit 

mientras que este está accediendo a un atributo a continuación, pasando como un parámetro:

MsgBox Application.Creator 

Como en el anterior ejemplo, los paréntesis son opcionales también en torno a parámetros si no hay necesidad de tratar con el valor de retorno:

Application.Goto Worksheets("Sheet2").Range("A1") 

pero es necesario si se utiliza el valor de retorno:

Cuestiones relacionadas