Estoy escribiendo sobre la sintaxis del lenguaje. ¿Existe un idioma en el que los parámetros se colocan dentro del nombre del método?

29

en JavaScript:

function getTopCustomersOfTheYear(howManyCustomers, whichYear) {
   // Some code here.
}
getTopCustomersOfTheYear(50, 2010);

Cía#:

public List<Customer> GetTopCustomersOfTheYear(int howManyCustomers, 
 int whichYear)
{
   // Some code here
}
List<Customer> customers = GetTopCustomersOfTheYear(50, 2010);

en PHP:

public function getTopCustomersOfTheYear($howManyCustomers, $whichYear)
{
   // Some code here
}
$customers = getTopCustomersOfTheYear(50, 2010);

¿Hay algún lenguaje que admita esta sintaxis?

function GetTop(x)CustomersOfTheYear(y)
{
    // Some code here
}
returnValue = GetTop(50)CustomersOfTheYear(2010);

¿No es una forma más semántica y más legible de escribir una función?

Actualización: la razón por la que hago esta pregunta es que estoy escribiendo un artículo sobre una nueva sintaxis para un nuevo idioma. Sin embargo, pensé que tener esa sintaxis para declarar métodos podría ser mejor y más amigable para los desarrolladores y disminuiría la curva de aprendizaje del lenguaje, debido a que está más cerca del lenguaje natural. Solo quería saber si esta característica ya se ha contemplado o no.

Saeed Neamati
fuente
12
Puede ser más fácil de leer, una vez que te acostumbras al idioma, pero me parece que sería difícil escribir un analizador correcto para eso.
Mason Wheeler
2
¿Qué quiere decir con "marcadores de posición"? Esta pregunta es difícil de entender tal como se plantea, aunque el último ejemplo de código recuerda a Objective-C y SmallTalk.
greyfade
3
AFAIK Smalltalk fue el primer idioma que utilizó esta sintaxis exclusivamente como 'hello world' indexOf: $o startingAt: 6o Rectangle width: 100 height: 200. Por cierto, ¿qué hay de malo en esta pregunta?
maaartinus
8
Si mueves un paréntesis, obtienes: returnValue = GetTop(50, CustomersOfTheYear(2010))lo que me parece igualmente legible, y en realidad más flexible / ortogonal. ... y sí, es una sintaxis normal.
Dagnelies
2
@arnaud: estoy totalmente de acuerdo. La sintaxis propuesta es solo una solución para la falta de descomposición.
back2dos

Respuestas:

41

Si y si. Sí, hay un lenguaje así, y sí, muchas personas lo encuentran más legible una vez que se acostumbran.

En Objective-C, el método sería:

- (NSArray*)getTop:(int)count customersOfTheYear:(Year)year;

Ese es en realidad un ejemplo bastante ingenioso que no se lee muy bien, así que aquí hay uno mejor del código real:

+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;

Que el prototipo de un método que devuelve una nueva instancia de UIColor utilizando los valores rojo, verde, azul y alfa. Lo llamarías así:

UIColor *violet = [UIColor colorWithRed:0.8 green:0.0 blue:0.7 alpha:1.0];

Lea más sobre nombres de mensajes con parámetros intercalados en el lenguaje de programación Objective-C .

Caleb
fuente
16
La primera vez que lo leí en Objective CI pensé que era inteligente, pero en realidad se llamaron parámetros que se hicieron más rígidos y difíciles de manejar. Aparte de eso, buena respuesta.
ZJR
2
Un ejemplo de cómo se invoca el método no estaría mal.
greyfade
3
@ZJR, a pesar de la opinión de Wikipedia de lo contrario , el estilo de Obj-C es como parámetros con nombre, pero diferente. En el ejemplo anterior, el método de nombre es: +colorWithRed:blue:green:alpha:. Me pasó a utilizar los nombres de los parámetros que coinciden con el método, pero podría fácilmente haber utilizado r, b, g, y a. Con parámetros con nombre como ofertas de JavaScript, usaría los nombres reales dados para acceder a los valores. Los parámetros de nombres verdaderos también se pueden dar en cualquier orden, y los parámetros pueden ser opcionales. Muy similar, sí, pero fundamentalmente diferente.
Caleb
2
Estaba pensando en Python: color(r=0xFF,g=0xFF,b=0x55)o color(b=0x32,r=0x7F,a=.5,g=0xFF)así sucesivamente. Llamemos a esos parámetros muy nombrados , entonces. :)
ZJR
3
@ZJR, su ejemplo de Python es correcto, eso es exactamente lo que yo llamaría "parámetros con nombre". Solo digo que Obj-C realmente no te da eso en absoluto. La sintaxis se parece mucho a los parámetros con nombre de JavaScript porque el método se divide en partes, y cada parte tiene dos puntos, pero en realidad no es eso en absoluto . Los nombres en Obj-C son parte del nombre del método, no nombres que pueden usarse para referirse a los parámetros en la implementación; el orden importa; Los parámetros no son opcionales. Sospecho que probablemente estamos más de acuerdo.
Caleb
25

Respuesta: smalltalk

http://en.wikipedia.org/wiki/Smalltalk

'hello world' indexOf: $o startingAt: 6 es como el de Java "hello world".indexOfStartingAt(o, 6)

Rectangle width: 100 height: 200 es como el de Java new Rectangle(100, 200)

La sintaxis es ... expression word1: parm1 word2: parm2 word3: parm3 ...El nombre del método llamado es la concatenación de todas las palabras.

Jeff Grigg
fuente
17

Creo que está buscando la abstracción llamada " interfaz fluida (por la presente estoy haciendo un comentario, originalmente hecho por @Jesper, a una" respuesta ")". Este patrón ahora común se ha implementado con éxito en muchos lenguajes, de los cuales Objective-C es solo uno.

Aquí hay un ejemplo bastante limpio:

Person bo = new Person();
bo.Set.FirstName("Bo").LastName("Peep").Age(16).Size("Little").LostHerSheep();

Se puede ver cómo algo como esto puede ser implementado en Randy Patterson 's Cómo diseñar una interfaz fluida .

Andre Vianna ofrece una breve historia y luego analiza las posibles implementaciones en dos partes más del artículo, incluida mucha información útil. Vianna vuelve a la vieja idea que encontré por primera vez en Smalltalk 80 llamada "en cascada ", que permitía enviar múltiples mensajes al mismo objeto. Se veía así:

aThing one: 'one';
  two: 'two';
  other.

Posteriormente, la conexión en cascada evolucionó hacia el " encadenamiento de métodos " , donde "Hacemos que los métodos modificadores devuelvan el objeto host, de modo que se puedan invocar múltiples modificadores en una sola expresión " . El encadenamiento de métodos más tarde se convirtió en el concepto de interfaz fluido que conocemos y usamos con frecuencia hoy en día. . Lo que planeas hacer se ve muy similar.

Ayende Rahien analiza cómo la "interfaz fluida" puede diferir significativamente de la "cadena de métodos" para merecer su propio nombre .

Las interfaces fluidas se ven comúnmente en algunas de las nuevas herramientas utilizadas en el desarrollo impulsado por el comportamiento (BDD) e incluso han llegado a NUnit , una importante herramienta de prueba de unidades .NET, en su nuevo modelo de afirmación basado en restricciones .

Estos enfoques básicos se han implementado posteriormente en otros lenguajes, incluidos Ruby, Python, C #, Objective-C y Java . Para implementar algo similar, querrá estudiar la idea del " cierre ", que es bastante fundamental para el encadenamiento y la fluidez.

Quizás puedas mejorar estos modelos; así es como obtenemos excelentes idiomas nuevos. Aún así, ¡creo que comprender completamente el encadenamiento de métodos y las interfaces fluidas te dará un excelente punto de partida para desarrollar tus ideas!

John Tobler
fuente
2
+1 para la respuesta más investigada hasta el momento, aunque puede ser útil agregar ejemplos y reformular la legibilidad.
haylem
@haylem, ¡gracias por hacerme volver y agregar ejemplos y un poco más de detalle!
John Tobler
3
Votado porque es una buena descripción del estilo fluido, pero tenga en cuenta que esto realmente no es lo que pregunta el OP. Mientras lo leo, la pregunta se relaciona con parámetros intercalados con partes del nombre de una sola función o método . Tenga en cuenta la declaración de la función propuesta: function GetTop(x)CustomersOfTheYear(y). Esta es una función única, no llamadas encadenadas a dos funciones diferentes.
Caleb
@Caleb Creo que aquí está tratando de señalar que estos parámetros infijos son una forma inflexible de hacer una interfaz fluida (esta respuesta) o parámetros con nombre (otra respuesta). Hasta ahora no he visto ninguna ventaja para ellos de que una interfaz fluida / parámetros con nombre no pueden mejorar.
Izkata
16

Objective-C hace eso. Aquí hay un prototipo típico:

- (void) areaWithHeight: (float) height andWidth: (float) width;

Así es como se llama este método:

float area = [self areaWithHeight: 75 andWidth: 20];

Objective-C se usa principalmente con Cocoa para Mac OS X y Cocoa Touch para iOS, pero gcc construirá el código de Objective-C en casi todas las plataformas en las que trabaja gcc.

Mike Crawford
fuente
Lo siento, esa bala debería haber sido un guión. Supongo que los guiones en el texto de respuesta se toman como marcado. Los guiones en Objective-C se usan para declarar métodos que pertenecen a un objeto - [foo bar: x] donde foo es un objeto o una instancia de clase - mientras que los signos más se usan para métodos de clase, a lo que C ++ se refiere como funciones miembro estáticas.
Mike Crawford
13

En Common lisp, puede definir argumentos de palabras clave para una función como esta:

(defun area (&key width height)
    (* width height))

La función se llama así:

(area :width 2 :height 3)

En Ada no necesita una declaración especial: puede llamar a cualquier procedimiento o función alternativamente enumerando los argumentos en orden o nombrando los argumentos de esta manera:

a := area(width => 2, height => 3);

Finalmente, la biblioteca de impulso incluye una capa de hacks para agregar la función a C ++: http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html

han
fuente
5

No pude encontrar el nombre, pero hay un patrón de diseño para lograr algo similar, donde una llamada a la función devuelve un nuevo objeto modificado como se describe. Por ejemplo:

query = db.getTopCustomers(50).forYear(2010);

No se usa con mucha frecuencia porque sus datos deben ser muy ortogonales para evitar una complejidad inmanejable bajo el capó, pero pueden ser útiles en las circunstancias correctas.

Karl Bielefeldt
fuente
66
Esto se llama estilo de diseño de interfaz fluido .
Jesper
@Jesper, lo que veo es muy similar al encadenamiento de jQuery. Estoy en lo cierto?
Saeed Neamati
Sí, @Saeed, jQuery usa este estilo.
Karl Bielefeldt el
5

Python tiene parámetros de palabras clave. Ejemplo de definición de función

def getTopCustomers(count,year):
...

Ejemplo de llamada de función

x = getTopCustomers(year=1990, count=50)

(Entiendo que esto no está del todo en el espíritu de la pregunta original, pero si los parámetros de palabras clave en lisp califican, así que hazlo. En Smalltalk y Objective-C, sin embargo, las palabras clave entre argumentos son realmente parte del nombre / búsqueda de la función .)

David Andersson
fuente
Personalmente, me gusta más, porque te da la opción de llamar a la función sin los nombres de los parámetros si conoces el orden de los parámetros
Pablo Mescher
4

Agda tiene notación mixfix

if_then_else x y z = case x of
                     True -> y
                     False -> z

 if cond then x else y

Cada vez que la función se nombra con un guión bajo, se puede dividir en dos partes con un argumento en el medio

Daniel Gratzer
fuente
4

Si bien no es un lenguaje de programación per se , Cucumber toma parámetros en el medio de los nombres de las funciones, que pueden incluir espacios y deben parecerse al inglés.

Sin embargo, las 'funciones' se definen en Ruby

# definition
Given /^I calculate (.*) times (.*)$/ do |x, y|
    @result = x.to_i * y.to_i
end

Then /^the result should be (.*)$/ do |v|
    @result.should == v.to_i
end

# usage
Scenario:
    Given I calculate 6 times 9
    Then the result should be 42
configurador
fuente
4

En TeX puede definir macros que tengan un "patrón de argumento" que básicamente significa que su protocolo de llamadas es gratuito. Para su ejemplo específico, podría usar

\def\getTopCustomers#1OfTheYear#2;{%
  The #1 top customers of the year #2.
}
\getTopCustomers 50 OfTheYear 2010;

Tenga en cuenta que también es posible deshacerse de él ;si acepta jugar con registros:

\newcount\customers
\newcount\year
\def\getTopCustomers#1OfTheYear{%
  \customers#1\relax
  \afterassignment\reallyGetTopCustomersOfTheYear
  \year
}
\def\reallyGetTopCustomersOfTheYear{%
  The {\the\customers} top customers of the year {\the\year}.
}
\getTopCustomers 50 OfTheYear 2010

TeX le permite reconfigurar su lexer, y gracias a la \afterassignmentmacro que utilicé anteriormente, puede usar los procedimientos integrados para lex números. Es muy útil definir protocolos de llamadas muy concisos . Por ejemplo, es muy plausible escribir macros TeX que comprendan la notación Markdown para tablas.

Ahora pregunta "¿cómo accedo a mi base de datos donde los clientes están almacenados desde TeX?", Pero esta es otra pregunta. :)

En Common lisp, definitivamente es posible definir una querymacro que le permita escribir

(query getTopCustomers 50 OfTheYear 2010)

donde getCustomers y OfTheYear se interpretan como símbolos. Es entonces el trabajo de la macro darle sentido. El lisp común es excelente en el dominio de la legibilidad del código (¡sí, lo digo en serio!) Porque el sistema macro permite crear fácilmente pseudo-idiomas ajustados para su aplicación. (Creo que se llaman lenguajes de aplicación).

PD: Parece que nadie citó C ++. Lo más cercano que puede llegar (sin el preprocesador) es

query.getTopCustomers(50).OfTheYear(2010):

el truco es dejar que getTopCustomersdevuelva una referencia query(o cualquier otra cosa) que también implemente OfTheYear. Puede crear este ejemplo en un lenguaje de consulta pequeño, pero luego debe identificar las propiedades finales (devolver un valor) o agregar un finalisemétodo (realizar la búsqueda y devolver el valor). Si lo desea, también puede imitar los controladores de flujo de STL y escribir cosas como

query << getTopCustomers(50) << OfTheYear(2010) << flush;

pero esto nuevamente va en la dirección de los lenguajes de aplicación.

Editar: Pasé por alto las respuestas de @han, que también citan Common Lisp y C ++ (¡pero no TeX!).

Michael Grünewald
fuente
2

En JavaScript o en cualquier otro lenguaje que admita cierres, puede crear una función como esta:

function getTopCustomersFunc(count) {
    return function(year) {
       // run some query, return count customers from year
    }
}
var top20Func = getTopCustomersFunc(20);
var top20Customers2005 = top20Func(2005);
var top20Customers2008 = top20Func(2008);
jiggy
fuente
1
+1 porque esto es interesante, pero recuerde que el '20' en top20Func ya no es un parámetro sino parte del nombre que le recuerda el parámetro. Usted podría fácilmente decir: var top5Func = getTopCustomersFunc(37);. El '5' es engañoso aquí, pero el código funciona exactamente igual que si la variable hubiera sido nombrada top37Func.
Caleb
1

Esto depende de su definición de "lenguaje", pero el marco de prueba de robotframework le permite definir palabras clave de esta manera. De su documentación sobre argumentos incrustados :

Select ${animal} from list | Open page | pet selection
                            | Select item from list | animal_list | ${amimal}

Lo anterior declara una nueva palabra clave (esencialmente una función) llamada "select $ {animal} from list" donde '$ {animal}' es un parámetro. Lo llamas como "seleccionar gato de la lista"

Bryan Oakley
fuente
Esto me parece declaraciones SQL. +1
Saeed Neamati
1

Informar 7.

To create (employee - a person) being paid (salary - a number):
    say "Welcome to your new job, [name of employee]!";
    choose a blank row from the table of employees;
    now the paid entry is the salary;
    now the name entry is the name of the employee.

Y así.

Ron Newcomb
fuente
3
Esto no explica exactamente cómo funciona la sintaxis del lenguaje. Muchas personas no están familiarizadas con el lenguaje Inform y no pueden distinguir los parámetros de la llamada o su uso en otras áreas del código.
Estoy un poco intrigado por este lenguaje. La respuesta fue bastante corta con solo una muestra de código no elaborada, pero también lo fueron las muestras dadas por el OP (aunque con lenguajes más convencionales). Wiki tiene un buen artículo para leer al respecto.
YoYo
0

Las palabras clave de Common Lisp ya se han mencionado, pero las macros de Common Lisp también permiten esto con bastante facilidad:

(defmacro get-my-element (from list at index)
  `(nth ,index ,list))

Esto se puede llamar así:

(get-my-element from '(a b c) at 1) ;returns B

Sin embargo, una cosa a tener en cuenta es que los términos fromy atno se aplican. Tiene que haber algo allí, omitirlos por completo es un error, pero dado que la macro simplemente los descarta, no importa mucho lo que están más allá de la legibilidad (lo cual es importante):

(get-my-element from '(a b c) 3 1) ;also returns B
8bittree
fuente
-2

En Clojure, es común usar argumentos de palabras clave para situaciones como esta, por ejemplo:

(get-customers :top 50 :year 2010)

Los argumentos de las palabras clave son bastante flexibles, pueden ser opcionales y tener valores predeterminados especificados, etc.

mikera
fuente
-4

Puedes emular esto en python. Por ejemplo,

def GetTop(customers, ofYear):
  #write some code here to get the customers

print GetTop(customers=50 ofYear=2010)

o incluso

def GetTop(**args):
  #write some code here using the same parameter names as above

print GetTop({customers: 50, ofYear: 2010})
codificador108
fuente
1
La sintaxis en su segundo ejemplo es incorrecta. Además, alguien ya ha publicado esto.
Winston Ewert
esto simplemente repite el punto hecho (y mucho mejor explicado) en esta respuesta anterior que fue publicada 3 años antes
mosquito