Estou escrevendo sobre sintaxe de idioma. Existe um idioma no qual os parâmetros são colocados dentro do nome do método?

29

em JavaScript:

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

em c #:

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

em PHP:

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

Existe algum idioma por aí que suporte esta sintaxe:

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

Não é uma forma mais semântica e mais legível de escrever uma função?

Atualização: O motivo pelo qual estou fazendo essa pergunta é que estou escrevendo um artigo sobre uma nova sintaxe para um novo idioma. No entanto, pensei que ter essa sintaxe para declarar métodos poderia ser mais agradável e mais amigável aos desenvolvedores e diminuiria a curva de aprendizado da linguagem, por estar mais próxima da linguagem natural. Eu só queria saber se esse recurso já foi contemplado ou não.

Saeed Neamati
fonte
12
Pode ser mais fácil ler, depois que você se acostumar com o idioma, mas me parece que seria difícil escrever um analisador correto para isso.
Mason Wheeler
2
O que você quer dizer com "espaços reservados"? Esta questão é difícil de entender como foi colocada, embora o último exemplo de código seja uma reminiscência de Objective-C e SmallTalk.
greyfade
3
O AFAIK Smalltalk foi o primeiro idioma usando essa sintaxe exclusivamente como 'hello world' indexOf: $o startingAt: 6ou Rectangle width: 100 height: 200. Aliás, o que há de errado com esta pergunta?
maaartinus 22/08
8
Se você mover um parêntese, obtém: o returnValue = GetTop(50, CustomersOfTheYear(2010))que me parece igualmente legível e, na verdade, mais flexível / ortogonal. ... e sim, é uma sintaxe normal.
Dagnelies
2
@arnaud: Eu concordo totalmente. A sintaxe proposta é apenas uma solução alternativa por falta de decomposição.
back2dos

Respostas:

41

Sim e sim. Sim, existe esse idioma e, sim, muitas pessoas o acham mais legível quando se acostumam.

No Objective-C, o método seria:

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

Na verdade, esse é um exemplo bem elaborado que não lê muito bem, então aqui está um melhor do código real:

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

Que o protótipo para um método que retorna uma nova instância UIColor usando os valores vermelho, verde, azul e alfa. Você chamaria assim:

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

Leia mais sobre nomes de mensagens com parâmetros intercalados em The Objective-C Programming Language .

Caleb
fonte
16
A primeira vez que li sobre isso no Objective CI achei que era inteligente, mas na verdade é chamado de parâmetros tornados mais rígidos e difíceis de gerenciar. Além disso, boa resposta.
ZJR 24/08
2
Um exemplo de como o método é chamado não seria errado.
greyfade
3
@ZJR, apesar da opinião da Wikipedia , o estilo do Obj-C é como parâmetros nomeados, mas diferentes. No exemplo acima, o método de nome é: +colorWithRed:blue:green:alpha:. Aconteceu de eu usar nomes para os parâmetros que correspondem ao método, mas eu poderia facilmente ter usado r, b, g, e a. Com parâmetros nomeados, como ofertas JavaScript, você usaria os nomes reais dados para acessar os valores. Os parâmetros de nomes verdadeiros também costumam ser fornecidos em qualquer ordem e os parâmetros podem ser opcionais. Tão semelhante, sim, mas fundamentalmente diferente.
Caleb
2
Eu estava pensando em python: color(r=0xFF,g=0xFF,b=0x55)ou color(b=0x32,r=0x7F,a=.5,g=0xFF)assim por diante. Vamos chamar esses parâmetros muito nomeados , então. :)
ZJR 25/08
3
@ZJR, seu exemplo de python está certo - é exatamente o que eu chamaria de "parâmetros nomeados". Só estou dizendo que o Obj-C realmente não lhe dá isso. A sintaxe se parece muito com os parâmetros nomeados do JavaScript, porque o método é dividido em partes e cada parte possui dois pontos, mas na verdade não é isso . Os nomes no Obj-C fazem parte do nome do método, não os nomes que podem ser usados ​​para se referir aos parâmetros na implementação; a ordem importa; parâmetros não são opcionais. Eu suspeito que provavelmente concordamos mais do que não.
Caleb
25

Resposta: smalltalk

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

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

Rectangle width: 100 height: 200 é como o de Java new Rectangle(100, 200)

A sintaxe é ... expression word1: parm1 word2: parm2 word3: parm3 ...O nome do método chamado é a concatenação de todas as palavras.

Jeff Grigg
fonte
17

Eu acredito que você está procurando a abstração chamada " interface fluente (por meio disso, estou levantando um comentário, originalmente feito por @Jesper, para uma" resposta ")". Esse padrão agora comum foi implementado com sucesso em vários idiomas, dos quais o Objective-C é apenas um.

Aqui está um exemplo bastante limpo:

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

Você pode ver como algo como isso pode ser implementado em Randy Patterson é como projetar uma interface fluente .

Andre Vianna fornece um breve histórico e discute as possíveis implementações em mais duas partes do artigo, incluindo muitas informações úteis. Vianna aponta de volta para a velha idéia que encontrei pela primeira vez no Smalltalk 80, chamada " cascata ", que permitiu o envio de várias mensagens para o mesmo objeto. Parecia assim:

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

Cascata, posteriormente, evoluiu para " encadeamento de método ", em que " tornar os métodos de modificação de devolver o objeto de host, para que vários modificadores pode ser invocado em uma única expressão. " Método encadeamento depois cresceu para se tornar a interface fluente conceito que conhecem e usam freqüentemente hoje . O que você planeja fazer é muito parecido.

Ayende Rahien discute como "interface fluente" pode diferir significativamente o suficiente de "encadeamento de métodos" para merecer seu próprio nome .

As interfaces fluentes são comumente vistas em algumas das novas ferramentas usadas no desenvolvimento orientado a comportamento (BDD) e chegaram até ao NUnit , uma importante ferramenta de teste de unidade .NET, em seu novo Modelo de declaração baseada em restrições .

Essas abordagens básicas foram implementadas posteriormente em outras linguagens, incluindo Ruby, Python, C #, Objective-C e Java . Para implementar algo semelhante, você deve estudar a idéia de " fechamento ", que é basicamente fundamental para encadeamento e fluência.

Talvez você possa melhorar esses modelos; é assim que obtemos ótimos novos idiomas. Ainda assim, acredito que entender completamente o encadeamento de métodos e as interfaces fluentes fornecerá um ótimo ponto de partida para você desenvolver suas idéias!

John Tobler
fonte
2
+1 para a maioria das respostas pesquisadas até o momento, apesar de adicionar exemplos e reformular a legibilidade para ajudar.
haylem
@haylem, obrigado por me fazer voltar e adicionar exemplos e um pouco mais de detalhes!
John Tobler
3
Promovido porque é uma boa descrição do estilo fluente, mas observe que isso realmente não é o que o OP está perguntando. Enquanto eu lia, a pergunta se relaciona a parâmetros intercalados com partes do nome de uma única função ou método . Note-se a declaração da função proposta: function GetTop(x)CustomersOfTheYear(y). Esta é uma função única, não chamadas em cadeia para duas funções diferentes.
Caleb
@ Caleb Acho que aqui ele está tentando apontar que esses parâmetros infix são uma maneira inflexível de fazer uma interface fluente (esta resposta) ou parâmetros nomeados (outra resposta). Até agora , não vi nenhuma vantagem para eles que uma interface fluente / parâmetros nomeados não possam fazer melhor.
Izkata
16

Objective-C faz isso. Aqui está um protótipo típico:

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

Aqui está como você chama esse método:

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

O Objective-C é usado principalmente com o Cocoa para Mac OS X e o Cocoa Touch para iOS, mas o gcc cria o código do Objective-C em praticamente todas as plataformas em que o gcc trabalha.

Mike Crawford
fonte
Lamentamos que o marcador deva ter sido um hífen. Eu acho que hífens no texto da resposta são tomados como marcação. Os hífens no Objective-C são usados ​​para declarar métodos que pertencem a um objeto - [foo bar: x] onde foo é um objeto ou instância de classe - enquanto sinais de adição são usados ​​para métodos de classe, ao que o C ++ se refere como funções-membro estáticas.
Mike Crawford
13

No Common lisp, você pode definir argumentos de palavras-chave para uma função como esta:

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

A função é chamada assim:

(area :width 2 :height 3)

No Ada, você não precisa de uma declaração especial - você pode chamar qualquer procedimento ou função alternativamente, listando os argumentos em ordem ou nomeando os argumentos assim:

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

Por fim, a biblioteca boost inclui uma camada de hacks para adicionar o recurso ao C ++: http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html

han
fonte
5

Não consegui encontrar o nome dele, mas há um padrão de design para realizar algo semelhante, em que uma chamada de função retorna um novo objeto modificado conforme descrito. Por exemplo:

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

Ele não é usado com muita frequência porque seus dados precisam ser muito ortogonais para evitar complexidade incontrolável, mas podem ser úteis nas circunstâncias certas.

Karl Bielefeldt
fonte
6
Isso é chamado de estilo de design de interface fluente .
Jesper
@ Jesper, o que vejo é muito semelhante ao encadeamento jQuery. Estou certo?
Saeed Neamati
Sim, @Saeed, o jQuery usa esse estilo.
Karl Bielefeldt
5

Python possui parâmetros de palavra-chave. Exemplo de definição de função

def getTopCustomers(count,year):
...

Exemplo de chamada de função

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

(Entendo que isso não está dentro do espírito da pergunta original, mas se os parâmetros de palavra-chave no lisp se qualificarem, faça isso. No Smalltalk e Objective-C, no entanto, as palavras-chave entre argumentos são realmente parte do nome da função / pesquisa .)

David Andersson
fonte
Pessoalmente, eu gosto mais disso, pois isso oferece a opção de chamar a função sem os nomes dos parâmetros, se você souber a ordem dos parâmetros.
Pablo Mescher
4

Agda possui notação mixfix

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

 if cond then x else y

Sempre que a função é nomeada com um sublinhado, ela pode ser dividida em duas partes com um argumento entre

Daniel Gratzer
fonte
4

Embora não seja uma linguagem de programação em si , o Cucumber usa parâmetros no meio dos nomes de funções, que podem incluir espaços e devem se parecer com o inglês.

As 'funções' são definidas no Ruby, no entanto

# 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
fonte
4

No TeX, você pode definir macros com um "padrão de argumento", o que basicamente significa que seu protocolo de chamada é gratuito. Para seu exemplo específico, você pode usar

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

Observe que também é possível se livrar do ; se você concordar em jogar com os 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

O TeX permite que você reconfigure seu lexer e, graças à \afterassignment macro que usei acima, você pode usar procedimentos internos para lex números. É muito útil definir protocolos de chamada muito concisos . Por exemplo, é muito plausível escrever macros TeX entendendo a notação Markdown para tabelas.

Agora você pergunta "como faço para acessar meu banco de dados onde os clientes estão armazenados no TeX?", Mas essa é outra questão. :)

No Common lisp, é definitivamente possível definir uma querymacro que permita escrever

(query getTopCustomers 50 OfTheYear 2010)

onde getCustomers e OfTheYear são interpretados como símbolos. O trabalho da macro é compreendê-la. O lisp comum é excelente no domínio da legibilidade do código (sim, quero dizer!) Porque o sistema macro permite criar facilmente pseudo-idiomas ajustados para a sua aplicação. (Eu acho que eles são chamados de linguagens de aplicativo.)

PS: Parece que ninguém citou C ++. O mais próximo que você pode chegar (sem o pré-processador) é

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

o truque é deixar getTopCustomersretorna uma referência query(ou qualquer outra coisa) que também implemente OfTheYear. Você pode criar este exemplo em uma linguagem de consulta pequena, mas é necessário identificar as propriedades finais (retornando um valor) ou adicionar um finalisemétodo (executando a pesquisa e retornando o valor). Se você quiser, também pode imitar os controladores de fluxo do STL e poder escrever coisas como

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

mas isso está novamente indo na direção das linguagens de aplicativo.

Edit: Eu ignorei @han respostas, que também citam Common Lisp e C ++ (mas não TeX!).

Michael Grünewald
fonte
2

Em JavaScript ou qualquer outro idioma que suporte fechamentos, você pode executar uma função 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
fonte
1
+1 porque isso é interessante, mas lembre-se de que o '20' no top20Func não é mais um parâmetro, mas parte do nome que lembra o parâmetro. Você poderia facilmente dizer: var top5Func = getTopCustomersFunc(37);. O '5' é enganoso aqui, mas o código funciona exatamente como se a variável tivesse sido nomeada top37Func.
Caleb
1

Isso depende da sua definição de "idioma", mas a estrutura de teste da estrutura do robô permite definir palavras-chave dessa maneira. De sua documentação sobre argumentos incorporados :

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

O texto acima declara uma nova palavra-chave (essencialmente uma função) chamada "selecione $ {animal} da lista" em que '$ {animal}' é um parâmetro. Você chama isso como "selecionar gato da lista"

Bryan Oakley
fonte
Isso me parece instruções 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.

E assim por diante.

Ron Newcomb
fonte
3
Isso não explica exatamente como a sintaxe do idioma funciona. Muitas pessoas não estão familiarizadas com o idioma Inform e não conseguem distinguir os parâmetros da chamada ou seu uso em outras áreas do código.
Estou meio intrigado com esse idioma. A resposta foi bastante curta com apenas uma amostra de código não elaborada, mas também foram as amostras fornecidas pelo OP (embora com idiomas mais convencionais). Wiki tem um bom artigo para ler sobre isso.
YoYo
0

As palavras-chave do Common Lisp já foram mencionadas, mas as macros do Common Lisp também permitem isso com bastante facilidade:

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

Isso pode ser chamado assim:

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

Uma coisa a observar, porém, é que os termos frome atnão são aplicados. Tem que haver algo lá, ignorá-los completamente é um erro, mas como a macro acaba descartando-os, não importa muito o que eles estejam além da legibilidade (o que é importante):

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

No Clojure, é comum usar argumentos de palavras-chave para situações como esta, por exemplo:

(get-customers :top 50 :year 2010)

Os argumentos da palavra-chave são bastante flexíveis, podem ser opcionais e têm padrões especificados etc.

Mikera
fonte
-4

Você pode emular isso em python. Por exemplo,

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

print GetTop(customers=50 ofYear=2010)

ou mesmo

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

print GetTop({customers: 50, ofYear: 2010})
coder108
fonte
1
A sintaxe no seu segundo exemplo está errada. Além disso, alguém já postou isso.
Winston Ewert 5/10
isso apenas repete ponto feito (e muito melhor explicado) em esta resposta antes que foi postado 3 anos antes
mosquito