J'écris sur la syntaxe du langage. Existe-t-il un langage dans lequel les paramètres sont placés à l'intérieur du nom de la méthode?

29

en JavaScript:

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

en C #:

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);

Existe-t-il un langage prenant en charge cette syntaxe:

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

N'est-ce pas une forme plus sémantique et plus lisible d'écrire une fonction?

Mise à jour: La raison pour laquelle je pose cette question est que j'écris un article sur une nouvelle syntaxe pour une nouvelle langue. Cependant, je pensais qu'avoir une telle syntaxe pour déclarer des méthodes pourrait être plus agréable et plus convivial pour les développeurs et diminuerait la courbe d'apprentissage du langage, en raison d'être plus proche du langage naturel. Je voulais juste savoir si cette fonctionnalité avait déjà été envisagée ou non.

Saeed Neamati
la source
12
Cela pourrait être plus facile à lire, une fois que vous vous serez habitué à l'idiome, mais il me semble qu'il serait difficile d'écrire un analyseur correct pour cela.
Mason Wheeler
2
Qu'entendez-vous par «espaces réservés»? Cette question est difficile à comprendre telle qu'elle est posée, bien que le dernier exemple de code rappelle Objective-C et SmallTalk.
greyfade
3
AFAIK Smalltalk a été le premier langage utilisant exclusivement cette syntaxe comme 'hello world' indexOf: $o startingAt: 6ou Rectangle width: 100 height: 200. Btw., Quel est le problème avec cette question?
maaartinus
8
Si vous déplacez une parenthèse, vous obtenez: returnValue = GetTop(50, CustomersOfTheYear(2010))ce qui me semble également lisible et en fait plus flexible / orthogonal. ... et oui, c'est une syntaxe tout à fait normale.
dagnelies
2
@arnaud: Je suis totalement d'accord. La syntaxe proposée n'est qu'une solution de contournement pour l'absence de décomposition.
back2dos

Réponses:

41

Oui et oui. Oui, il existe un tel langage, et oui, beaucoup de gens le trouvent plus lisible une fois qu'ils s'y sont habitués.

Dans Objective-C, la méthode serait:

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

C'est en fait un exemple assez artificiel qui ne lit pas très bien, alors voici un meilleur à partir du code réel:

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

C'est le prototype d'une méthode qui renvoie une nouvelle instance UIColor en utilisant les valeurs rouge, vert, bleu et alpha. Vous l'appeleriez comme ceci:

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

En savoir plus sur les noms de message avec des paramètres entrecoupés dans le langage de programmation Objective-C .

Caleb
la source
16
La première fois que j'ai lu à ce sujet dans Objective CI, je pensais que c'était intelligent, mais il s'agit en fait de paramètres nommés rendus plus rigides et plus difficiles à gérer. A part ça, bonne réponse.
ZJR
2
Un exemple de la façon dont la méthode est invoquée ne serait pas faux.
greyfade
3
@ZJR, malgré l'avis contraire de Wikipédia , le style d'Obj-C est comme des paramètres nommés, mais différents. Dans l'exemple ci - dessus, la méthode nom est: +colorWithRed:blue:green:alpha:. Je me trouvais à utiliser des noms pour les paramètres correspondant à la méthode, mais je pouvais aussi bien avoir utilisé r, b, get a. Avec des paramètres nommés tels que des offres JavaScript, vous utiliseriez les noms réels donnés pour accéder aux valeurs. Les paramètres de vrais noms peuvent également être généralement donnés dans n'importe quel ordre, et les paramètres peuvent être facultatifs. Si similaire, oui, mais fondamentalement différent.
Caleb
2
Je pensais à python: color(r=0xFF,g=0xFF,b=0x55)ou color(b=0x32,r=0x7F,a=.5,g=0xFF)ainsi de suite. Appelons donc ces paramètres très nommés . :)
ZJR
3
@ZJR, votre exemple python est exact - c'est exactement ce que j'appellerais des "paramètres nommés". Je dis juste que Obj-C ne vous donne vraiment pas ça du tout. La syntaxe ressemble beaucoup aux paramètres nommés de JavaScript car la méthode est divisée en parties, et chaque partie a deux points, mais ce n'est vraiment pas du tout cela . Les noms dans Obj-C font partie du nom de la méthode, pas des noms qui peuvent être utilisés pour faire référence aux paramètres dans l'implémentation; ordonner les questions; les paramètres ne sont pas facultatifs. Je soupçonne que nous sommes probablement plus d'accord que non.
Caleb
25

Réponse: smalltalk

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

'hello world' indexOf: $o startingAt: 6 est comme Java "hello world".indexOfStartingAt(o, 6)

Rectangle width: 100 height: 200 est comme Java new Rectangle(100, 200)

La syntaxe est ... expression word1: parm1 word2: parm2 word3: parm3 ...Le nom de la méthode appelée est la concaténation de tous les mots.

Jeff Grigg
la source
17

Je crois que vous recherchez l'abstraction appelée " interface fluide (je soulève par la présente un commentaire, initialement fait par @Jesper, à une" réponse ")." Ce modèle désormais commun a été implémenté avec succès dans de nombreux langages, dont Objective-C n'est qu'un.

Voici un exemple assez clair:

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

Vous pouvez voir comment quelque chose comme cela peut être mis en œuvre Randy Patterson « s Comment concevoir une interface fluide .

Andre Vianna donne un bref historique et discute ensuite des implémentations possibles dans deux autres parties d'article, y compris de nombreuses informations utiles. Vianna renvoie à l'ancienne idée que j'ai rencontrée pour la première fois dans Smalltalk 80, appelée « cascade », qui permettait d'envoyer plusieurs messages au même objet. Cela ressemblait à ceci:

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

Cascading ensuite évolué dans « chainage des méthodes », où nous « rendre les méthodes modificatrices retour l'objet hôte, de sorte que plusieurs modificateurs peuvent être invoquées dans une seule expression. » Enchaîner les méthodes plus tard a grandi pour devenir l' interface fluide concept que nous savons et l' utilisation souvent aujourd'hui . Ce que vous prévoyez de faire ressemble beaucoup.

Ayende Rahien explique comment "l'interface fluide" peut différer suffisamment de "l'enchaînement de méthodes" pour mériter son propre nom .

Des interfaces fluides sont couramment observées dans certains des nouveaux outils utilisés dans le développement axé sur le comportement (BDD) et ont même trouvé leur chemin dans NUnit , un outil majeur de test d'unité .NET, dans son nouveau modèle d'assertion basé sur des contraintes .

Ces approches de base ont ensuite été implémentées dans d'autres langages, notamment Ruby, Python, C #, Objective-C et Java . Pour mettre en œuvre quelque chose de similaire, vous voudrez étudier l'idée de « fermeture », qui est à peu près fondamentale pour le chaînage et la fluidité.

Vous pouvez peut-être améliorer ces modèles; c'est ainsi que nous obtenons de superbes nouvelles langues. Pourtant, je crois que la compréhension complète du chaînage des méthodes et des interfaces fluides vous donnera un excellent point de départ pour faire évoluer vos idées!

John Tobler
la source
2
+1 pour la réponse la plus recherchée jusqu'à présent, bien que l'ajout d'exemples et la reformulation pour plus de lisibilité puissent aider.
haylem
@haylem, merci de me faire revenir en arrière et ajouter des exemples et un peu plus de détails!
John Tobler,
3
Surévalué car c'est une bonne description du style fluide, mais veuillez noter que ce n'est vraiment pas ce que l'OP demande. À ma lecture, la question concerne l'entrecroisement de paramètres avec des parties du nom d'une seule fonction ou méthode . Notez la déclaration de la fonction proposée: function GetTop(x)CustomersOfTheYear(y). Il s'agit d'une fonction unique, et non d'appels chaînés à deux fonctions différentes.
Caleb
@Caleb Je pense qu'ici, il essaie de souligner que ces paramètres d'infixe sont un moyen inflexible de faire une interface fluide (cette réponse) ou des paramètres nommés (une autre réponse). Jusqu'à présent, je n'ai vu aucun avantage pour eux qu'une interface fluide / des paramètres nommés ne peuvent pas faire mieux.
Izkata
16

Objective-C fait cela. Voici un prototype typique:

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

Voici comment vous appelez une telle méthode:

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

Objective-C est principalement utilisé avec Cocoa pour Mac OS X et Cocoa Touch pour iOS, mais gcc créera du code Objective-C sur à peu près toutes les plateformes sur lesquelles gcc fonctionne.

Mike Crawford
la source
Désolé, cette balle aurait dû être un trait d'union. Je suppose que les tirets dans le texte de la réponse sont considérés comme des balises. Les tirets dans Objective-C sont utilisés pour déclarer les méthodes qui appartiennent à un objet - [foo bar: x] où foo est un objet ou une instance de classe - tandis que les signes plus sont utilisés pour les méthodes de classe, ce que C ++ appelle les fonctions membres statiques.
Mike Crawford
13

Dans Common lisp, vous pouvez définir des arguments de mots clés pour une fonction comme celle-ci:

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

La fonction est appelée comme ceci:

(area :width 2 :height 3)

Dans Ada, vous n'avez pas besoin d'une déclaration spéciale - vous pouvez appeler n'importe quelle procédure ou fonction en listant les arguments dans l'ordre, ou en nommant les arguments comme ceci:

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

Enfin, la bibliothèque boost comprend une couche de hacks pour ajouter la fonctionnalité à C ++: http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html

han
la source
5

Je n'ai pas pu trouver le nom de celui-ci, mais il y a un modèle de conception pour accomplir quelque chose de similaire, où un appel de fonction renvoie un nouvel objet modifié comme décrit. Par exemple:

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

Il n'est pas utilisé très souvent car vos données doivent être très orthogonales afin d'éviter une complexité ingérable sous le capot, mais peuvent être utiles dans les bonnes circonstances.

Karl Bielefeldt
la source
6
C'est ce qu'on appelle le style de conception d' interface fluide .
Jesper
@Jesper, ce que je vois est très similaire au chaînage jQuery. Ai-je raison?
Saeed Neamati
Oui, @Saeed, jQuery utilise ce style.
Karl Bielefeldt
5

Python a des paramètres de mots clés. Exemple de définition de fonction

def getTopCustomers(count,year):
...

Exemple d'appel de fonction

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

(Je comprends que ce n'est pas tout à fait dans l'esprit de la question d'origine, mais si les paramètres de mot-clé dans lisp se qualifient, faites-le. Dans Smalltalk et Objective-C, cependant, les mots-clés entre les arguments font vraiment partie du nom de la fonction / recherche .)

David Andersson
la source
Personnellement, j'aime mieux cela, car cela vous donne la possibilité d'appeler la fonction sans les noms de paramètres si vous connaissez l'ordre des paramètres
Pablo Mescher
4

Agda a une notation mixfix

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

 if cond then x else y

Chaque fois que la fonction est nommée avec un trait de soulignement, elle peut être divisée en deux parties avec un argument entre les deux.

Daniel Gratzer
la source
4

Bien que n'étant pas un langage de programmation en soi , Cucumber prend des paramètres au milieu des noms de fonction, qui peuvent inclure des espaces et sont censés ressembler à l'anglais.

Les «fonctions» sont cependant définies dans 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
configurateur
la source
4

Dans TeX, vous pouvez définir des macros ayant un «modèle d'argument», ce qui signifie essentiellement que votre protocole d'appel est libre. Pour votre exemple spécifique, vous pouvez utiliser

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

Notez qu'il est également possible de s'en débarrasser ;si vous acceptez de jouer avec les registres:

\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 vous permet de reconfigurer son lexer, et grâce à la \afterassignmentmacro que j'ai utilisée ci-dessus, vous pouvez utiliser des procédures intégrées pour les numéros lex. Il est très utile de définir des protocoles d'appel très laconiques . Par exemple, il est très plausible d'écrire des macros TeX comprenant la notation Markdown pour les tables.

Maintenant, vous demandez «comment puis-je accéder à ma base de données où les clients sont stockés à partir de TeX?», Mais c'est une autre question. :)

Dans Common lisp, il est définitivement possible de définir une querymacro vous permettant d'écrire

(query getTopCustomers 50 OfTheYear 2010)

où getCustomers et OfTheYear sont interprétés comme des symboles. Il appartient alors à la macro de lui donner un sens. Le lisp commun est excellent dans le domaine de la lisibilité du code (oui, je le pense!) Car le système de macro permet de créer facilement des pseudo-langages adaptés à votre application. (Je pense qu'ils sont appelés langages d'application.)

PS: Il semble que personne n'ait cité C ++. Le plus proche que vous pouvez obtenir (sans le préprocesseur) est

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

l'astuce consiste à laisser getTopCustomersrenvoie une référence sur query(ou toute autre chose) qui implémente également OfTheYear. Vous pouvez créer cet exemple jusqu'à un petit langage de requête, mais vous devez ensuite identifier les propriétés finales (renvoyer une valeur) ou ajouter une finaliseméthode (effectuer la recherche et renvoyer la valeur). Si vous en avez envie, vous pouvez également imiter les contrôleurs de flux de la STL et pouvoir écrire des choses comme

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

mais cela va de nouveau dans le sens des langages d'application.

Edit: j'ai ignoré les réponses @han, qui citent également Common Lisp et C ++ (mais pas TeX!).

Michael Grünewald
la source
2

En JavaScript ou dans tout autre langage prenant en charge les fermetures, vous pouvez utiliser une fonction comme celle-ci:

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
la source
1
+1 parce que c'est intéressant, mais rappelez-vous que le «20» dans top20Func n'est plus un paramètre mais une partie du nom qui vous rappelle le paramètre. Vous pourriez tout aussi bien dire: var top5Func = getTopCustomersFunc(37);. Le «5» est trompeur ici, mais le code fonctionne exactement comme si la variable avait été nommée top37Func.
Caleb
1

Cela dépend de votre définition du «langage», mais le cadre de test de robotframework vous permet de définir des mots clés de cette façon. De leur documentation sur les arguments intégrés :

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

Ce qui précède déclare un nouveau mot-clé (essentiellement une fonction) nommé "sélectionnez $ {animal} dans la liste" où '$ {animal}' est un paramètre. Vous l'appelez comme "sélectionner un chat dans la liste"

Bryan Oakley
la source
Cela me semble comme des instructions SQL. +1
Saeed Neamati
1

Informer 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.

Etc.

Ron Newcomb
la source
3
Cela n'explique pas exactement comment fonctionne la syntaxe du langage. De nombreuses personnes ne connaissent pas le langage Inform et ne peuvent pas distinguer les paramètres de l'appel ou de son utilisation dans d'autres domaines du code.
Je suis un peu intrigué par cette langue. La réponse a été plutôt courte avec seulement un échantillon de code non élaboré, tout comme les échantillons fournis par l'OP (bien qu'avec des langages plus conventionnels). Le wiki a un bel article à lire à ce sujet.
YoYo
0

Les mots-clés de Common Lisp ont déjà été mentionnés, mais les macros de Common Lisp permettent également cela assez facilement:

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

Cela peut alors être appelé ainsi:

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

Une chose à noter, cependant, est que les termes fromet atne sont pas appliqués. Il doit y avoir quelque chose , les sauter complètement est une erreur, mais comme la macro finit par les jeter, peu importe ce qu'ils sont au-delà de la lisibilité (ce qui est important):

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

Dans Clojure, il est courant d'utiliser des arguments de mots clés pour des situations comme celle-ci, par exemple:

(get-customers :top 50 :year 2010)

Les arguments des mots clés sont assez flexibles, ils peuvent être facultatifs et avoir des valeurs par défaut spécifiées, etc.

mikera
la source
-4

Vous pouvez émuler cela en python. Par exemple,

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

print GetTop(customers=50 ofYear=2010)

ou même

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

print GetTop({customers: 50, ofYear: 2010})
codeur 108
la source
1
La syntaxe de votre deuxième exemple est incorrecte. De plus, quelqu'un a déjà posté cela.
Winston Ewert
cela ne fait que répéter l'argument avancé (et beaucoup mieux expliqué) dans cette réponse précédente qui a été publiée 3 ans plus tôt
mnat