Any programming language with "strange" function call?
Asked Answered
A

16

9

I was wondering, is there any programming language where you can have function calls like this:

function_name(parameter1)function_name_continued(parameter2);

or

function_name(param1)function_continued(param2)...function_continued(paramN);

For example you could have this function call:

int dist = distanceFrom(cityA)to(cityB);

if you have defined distanceFromto function like this:

int distanceFrom(city A)to(city B)
{
   // find distance between city A and city B
   // ...
   return distance;
}

As far as I know, in C, Java and SML programming languages, this cannot be done.

Are you aware of any programming language that let's you define and call functions in this way?

Aril answered 22/7, 2010 at 10:43 Comment(3)
Could you be a bit more specifc on what this would accomplish ?Belostok
Well I think some function calls would be much easier to read like the 'distanceFromto' example. But I was just curious if such a programming language that let's you define such function exists.Aril
I think you need a better example to illustrate what you are trying to say because passing multi values into a function achieves the same thing and is equally (if not more) clear. EG. dist = distanceFrom(cityA, cityB)Archenteron
P
6

It looks an awful lot like Objective-C

- (int)distanceFrom:(City *)cityA to:(City *)cityB {
    // woah!
}
Propound answered 22/7, 2010 at 10:46 Comment(2)
Thanks for your answer. I guess, the code you wrote is the function definition. Could you also give an example of how this function is called?Aril
Almost identically to Smalltalk: dist = [metric distanceFrom: cityA to: cityB];Karlykarlyn
K
6

Sounds a lot like Smalltalk's syntax, (which would explain Objective-C's syntax - see kubi's answer).

Example:

dist := metric distanceFrom: cityA to: cityB

where #distanceFrom:to: is a method on some object called metric.

So you have "function calls" (they're really message sends) like

'hello world' indexOf: $o startingAt: 6. "$o means 'the character literal o"

EDIT: I'd said "Really, #distanceFrom:to: should be called #distanceTo: on a City class, but anyway." Justice points out that this couples a City to a Metric, which is Bad. There are good reasons why you might want to vary the metric - aeroplanes might use a geodesic while cars might use a shortest path based on the road network.)

Karlykarlyn answered 22/7, 2010 at 10:48 Comment(2)
A metric is a strategy to measure the distance between two points. There are multiple valid strategies, returning different valid results. metric#distanceFrom:to is the right technique; city#distanceTo is at best an approximation. What do cities know about distances to other cities?! Cities know their own positions, and metrics know about measuring distances between two positions.Pavonine
Justice, you're right. I like #distanceTo: because it's short - but that's a tradeoff that's probably not worth making, because it increases coupling (Cities know about non-City things) and it's not THAT much shorter than #distanceFrom:to:. Thanks!Karlykarlyn
C
4

For the curious, Agda2 has a similar, very permissive syntax. The following is valid code:

data City : Set where
  London : City
  Paris  : City

data Distance : Set where
  _km : ℕ → Distance

from_to_ : City → City → Distance
from London to London = 0 km
from London to Paris  = 342 km
from Paris  to London = 342 km
from Paris  to Paris  = 0 km

If

from Paris to London

is evaluated, the result is

342 km
Christoffer answered 22/7, 2010 at 11:15 Comment(0)
R
3

Looks a lot like a fluent interface or method chaining to me.

Rhaetian answered 22/7, 2010 at 11:18 Comment(0)
D
2

In Python, you can explicitly pass the name of the arguments you're calling the function with, which lets you pass them in a different order or skip optional arguments:

>>> l = [3,5,1,2,4]
>>> print l.sort.__doc__
L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
cmp(x, y) -> -1, 0, 1
>>> l.sort (reverse=True)
>>> l
[5, 4, 3, 2, 1]

This looks a lot like what the Objective C syntax is doing, tagging each argument to a function with its name.

Dishonor answered 22/7, 2010 at 11:0 Comment(0)
D
2

(see my very favourite personal effort - the final C++ approach at the end of this answer)

Language One

Objective-C but the calling syntax is [object message] so would look like:

int dist = [cities distanceFrom:cityA  to:cityB];

if you have defined distanceFromto function like this, within a cities object:

- (int)distanceFrom:(City *)cityA to:(City *)cityB 
  {
     // find distance between city A and city B
     // ...
     return distance;
  }

Language Two

I also suspect you could achieve something very close to this in the IO Language but I'm only just looking at it. You may also want to read about it in comparison to other languages in Seven Languages in Seven Weeks which has a free excerpt about IO.

Language Three

There's an idiom ("chaining") in C++ where you return temporary objects or the current object that is used to replace keyword arguments, according to The Design and Evolution of C++ and looks like this:

int dist = distanceFrom(cityA).to(cityB);

if you have defined distanceFrom function like this, with a little helper object. Note that inline functions make this kind of thing compile to very efficient code.

class DistanceCalculator
{
public:
    DistanceCalculator(City* from) : fromCity(from) {}

    int to(City * toCity) 
    {
         // find distance between fromCity and toCity
         // ...
         return distance;
    }

private:
    City* fromCity;
};


inline DistanceCalculator distanceFrom(City* from)
{
    return DistanceCalculator(from);
}

Duhh, I was in a hurry earlier, realised I can refactor to just use a temporary object to give the same syntax:

class distanceFrom
{
public:
    distanceFrom(City* from) : fromCity(from) {}

    int to(City * toCity) 
    {
         // find distance between fromCity and toCity
         // ...
         return distance;
    }

private:
    City* fromCity;
};

MY FAVOURITE and here's an even more inspired C++ version that allows you to write

int dist = distanceFrom cityA to cityB;

or even

int dist = distanceFrom cityA to cityB to cityC;

based on a wonderfully C++ ish combination of #define and classes:

#include <vector>
#include <numeric>
class City;
#define distanceFrom DistanceCalculator() <<
#define to <<

class DistanceCalculator
{
public:

    operator int() 
    {
         // find distance between chain of cities
         return std::accumulate(cities.begin(), cities.end(), 0);
    }
    
    DistanceCalculator& operator<<(City* aCity)
    {
        cities.push_back(aCity);
        return *this;
    }

private:
    std::vector<City*> cities;
};

NOTE this may look like a useless exercise but in some contexts it can be very useful to give people a domain-specific language in C++ which they compile alongside libraries. We used a similar approach with Python for geo-modeling scientists at the CSIRO.

Dolt answered 22/7, 2010 at 11:6 Comment(2)
I have no knowledge of C++ but the assignment: int dist = distanceFrom cityA to cityB; seems neat! Thank you for taking time to answer at my question.Aril
It's this cleverness about C++ that always makes me smile and cringe simultaneously.Clarethaclaretta
F
2

C# 4.0's Named and Optional Arguments feature allows you to achieve something pretty similar:

public static int Distance(string from, string to, string via = "")
{
   ...
}

public static void Main()
{
   int distance;

   distance = Distance(from: "New York", to: "Tokyo");
   distance = Distance(to: "Tokyo", from: "New York");
   distance = Distance(from: "New York", via: "Athens", to: "Tokyo");
}
Fusty answered 22/7, 2010 at 11:11 Comment(3)
That looks so much like Common Lisp's keyword parameters, it's scary: (distance from: "New York" to: "Tokyo")Karlykarlyn
Keywords start with :, not end with it, so it'd be (distance :from "New York" :to "Tokyo"). But yeah.Obituary
Python has keyword arguments, too.Clarethaclaretta
P
1

You can do this in C, albeit unsafely:

struct Arg_s
    {
    int from;
    int to;
    };

int distance_f(struct Arg_s args)
    {
    return args.to - args.from;
    }

#define distance(...) distance_f( ((struct Arg_s){__VA_ARGS__}) )
#define from_ .from =
#define to_ .to =

uses compound literals and designated initializers.

printf("5 to 7 = %i\n",distance(from_ 5, to_ 7));
// 5 to 7 = 2
Phonometer answered 2/8, 2010 at 1:45 Comment(1)
It is like the saying goes: just because you can, doesn't mean you should.Phonometer
J
1

3 of the 4 confederated languages from RemObjects in their Elements Compiler have this capability in precisely the OP's requested syntax (to support Objective-C runtime, but made available to all operating systems).

in Hydrogene (an extended C#) https://docs.elementscompiler.com/Hydrogene/LanguageExtensions/MultiPartMethodNames

in Iodine (an extended Java) https://docs.elementscompiler.com/Iodine/LanguageExtensions/MultiPartMethodNames

in Oxygene (an extended ObjectPascal), scroll down to Multi-Part Method Names section https://docs.elementscompiler.com/Oxygene/Members/Methods

Jurisprudent answered 10/4, 2018 at 16:49 Comment(0)
A
0

This looks similar to function overloading (C++/C#)/default parameters (VB).

Default Parameters allow the person defining the function to set defaults for the latter parameters:

e.g. c# overloading:

int CalculateDistance(city A, city B, city via1, city via2) 
{....}

int CalculateDistance(city A, city B) 
{
  return CalculateDistance(city A, city B, null, null)
}
Arterialize answered 22/7, 2010 at 10:51 Comment(0)
R
0

You can use a member function for this.

cityA.distance_to(cityB);

That's valid code in C++, C(with a little tweaking), C#, Java. Using method chains, you can do:

cityA.something(cityB).something(cityC).something(cityD).something(cityE);
Redman answered 22/7, 2010 at 10:58 Comment(0)
J
0

In SML you could simply make "to" some value (unit, for example), and "distanceFrom" a curried function that takes three parameters. For example:

val to = ()
fun distanceFrom x _ y = (* implementation function body *)

val foo = distanceFrom cityA to cityB

You could also take advantage of the fact that SML doesn't enforce naming conventions on datataype constructors (much to many peoples' annoyance), so if you want to make sure that the type system enforces your custom syntax:

datatype comp = to

fun distanceFrom x to y = (* implementation *)

val foo = distanceFrom cityA to cityB (* works *)
val foo' = distanceFrom cityA cityB (* whoops, forgot 'to' - type error! *)
Janettajanette answered 22/7, 2010 at 11:10 Comment(1)
Although I wasn't looking for a curried function. I really found interesting and nice the trick you did with datatype comp = to :) (+1 for this)Aril
L
0

You could do this in Scheme or LISP using macros.

The form will be something like:

(DISTANCE-FROM city-a TO city-b)

The symbols in uppercase denotes syntax.

You could even do something like 'named parameters':

(DISTANCE TO city-a FROM city-b)
(DISTANCE FROM city-a TO city-b)
Lashonlashond answered 22/7, 2010 at 11:18 Comment(3)
You could happily have (distance :from 'city-a :to 'city-b) with this: (defun distance (&key from to) ...) (but this doesn't address the question, because the function's still called DISTANCE).Karlykarlyn
@Aril I don't know what I was thinking. You can't do this with the C proprocessor. It must be done at the tokenized level, the level Lisp macros operate on.Spurgeon
@functional,@reinierpost, I'm fairly sure you can, using compound literals and designated initializers.Phonometer
D
0

Tcl allows you to do something like this:

proc distance {from cityA to cityB} {...}
set distance [distance from "Chicago IL" to "Tulsa OK"]

I'm not sure if that's quite what you are thinking of though.

Disassembly answered 22/7, 2010 at 13:37 Comment(0)
M
0

You can do it in Java, Use Builder pattern that appears in the book Effective Java by Joshua Bosch (this is second time I put this link in SO, I still didn't use that patern, but looks great)

Myocarditis answered 4/8, 2010 at 19:17 Comment(0)
C
0

Well, in Felix you can implement this in two steps: first, you write an ordinary function. Then, you can extend the grammar and map some of the new non-terminals to the function.

This is a bit heavyweight compared to what you might want (welcome to help make it easier!!) I think this does what you want and a whole lot more!

I will give a real example because the whole of the Felix language is actually defined by this technique (below x is the non-terminal for expressions, the p in x[p] is a precedence code):

// alternate conditional
x[sdollar_apply_pri] := x[stuple_pri] "unless" x[let_pri] 
  "then" x[sdollar_apply_pri] =>#
  "`(ast_cond ,_sr ((ast_apply ,_sr (lnot ,_3)) ,_1 ,_5))";

Here's a bit more:

// indexes and slices
x[sfactor_pri] := x[sfactor_pri] "." "[" sexpr "]" =># 
  "`(ast_apply ,_sr (,(noi   'subscript) (,_1 ,_4)))";
x[sfactor_pri] := x[sfactor_pri] "." "[" sexpr "to" sexpr "]" =># 
  "`(ast_apply ,_sr (,(noi 'substring) (,_1 ,_4 ,_6)))";
x[sfactor_pri] := x[sfactor_pri] "." "[" sexpr "to" "]" =># 
  "`(ast_apply ,_sr (,(noi 'copyfrom) (,_1 ,_4)))";
x[sfactor_pri] := x[sfactor_pri] "." "[" "to" sexpr "]" =># 
  "`(ast_apply ,_sr (,(noi 'copyto) (,_1 ,_5)))";

The Felix grammar is ordinary user code. In the examples the grammar actions are written in Scheme. The grammar is GLR. It allows "context sensitive keywords", that is, identifiers that are keywords in certain contexts only, which makes it easy to invent new constructs without worrying about breaking existing code.

Perhaps you would like to examine Felix Grammar Online.

Clotheshorse answered 25/12, 2011 at 23:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.