Variadic function

from Wikipedia, the free encyclopedia

In programming languages , a variadic function is a function , procedure or method with an indefinite character, i.e. those whose number of parameters is not already specified in their declaration .

In some languages ​​such as C , C ++ , Java, and Lua , this is indicated in the function declaration with an ellipsis , called an ellipse . Any number of arguments (or none) can be passed in place of the ellipse . Variadic functions are useful, for example, when linking several character strings or when adding up series of numbers and generally with operations that can in principle be applied to any number of operands.

Depending on the conventions of the programming language, the arguments can have different data types (e.g. in JavaScript) or must have the same data type (e.g. in Java).

Implementation in various programming languages

C.

Access to variadic parameters takes place via special macros . Some library functions of C are declared with an ellipse, since there is no possibility of function overloading in C, examples are the library functions printf()and scanf()for formatted output and input. A fundamental problem with this mechanism is that the called function has no information about the number and type of arguments passed. The programmer must therefore take additional measures (such as the format string in printf()) to ensure that the arguments are correctly interpreted and that no more arguments are processed than were actually available. In addition, at least one fixed parameter must be specified in front of the ellipse.

Before they are passed to the function, the function parameters are automatically converted into larger types according to the following scheme:

Output type Target type
char, signed char, short int
unsigned char, unsigned short unsigned int
float double

All other types are retained.

For example, one could calculate the mean value of any number of integers in C using the following function:

#include <stdarg.h>

double mittelwert(int num_zahlen, ...)
{
    va_list argumente;
    int i;
    double summe = 0;

    va_start(argumente, num_zahlen); /* Benötigt den letzten bekannten Parameter, um die Speicheradresse der anderen Parameter berechnen zu können */
    for (i = 0; i < num_zahlen; i++) {
        summe += va_arg(argumente, double); /* Inkremetiert argumente zum nächsten Argument */
    }
    va_end(argumente);

    return summe / num_zahlen;
}

C ++

C-style ellipses are still possible in C ++, but they are considered obsolete because C ++ offers more elegant options for function overloading and the concept of default arguments . Ellipses are also considered bad style because they don't offer type safety . In addition, not all data types can be passed as part of an ellipse.

In C ++ there is also the option of using variadic function templates. These are type-safe, but more complex to use because the so-called "template parameter packs" have to be resolved recursively:

unsigned produkt(unsigned u) {return u;}  // Rekursions-Ende

template<typename... Args>
unsigned produkt(unsigned u1, Args... rest)
{
    return u1 * produkt(rest...);
}

// Aufruf:
unsigned p = produkt(1,2,3,4,5);

[obsolete] So-called "fold expressions" are introduced in C ++ 17 , with which variadic functions can be greatly simplified as in the example above:

template<typename... Args>
unsigned produkt(Args... factors)
{
    return (1u * ... * factors);
}

Furthermore, ellipses can often be replaced by one std::initializer_list, whereby the syntax differs slightly when called, since the arguments must be enclosed in curly brackets:

unsigned produkt(std::initializer_list<unsigned> factors)
{
    return std::accumulate(factors.begin(), factors.end(), 1u, std::multiplies<unsigned>);
}

// Aufruf:
unsigned p = produkt({1,2,3,4,5});

C #

In C # , the keyword is paramsused in the declaration . The type is also specified. Such a method can be passed a comma-separated list (this list can also be empty). paramsNo further parameters are allowed after the keyword . In addition, it can only appear once in the method declaration.

public class Summe
{
    public static int sum(params int[] list)
    {
        int result = 0;

        for (int i = 0; i < list.Length; i++)
        {
            result += list[i];
        }

        return result;
    }

    static void Main()
    {
        int a = sum();             // Ergebnis: a = 0
        int b = sum(1);            // Ergebnis: b = 1
        int c = sum(1, 2, 3, 4);   // Ergebnis: c = 10
    }
}

Go

The Go language allows the declaration of variadic functions by appending an ellipse ...to the name of the last parameter. Any number of parameters of the specified type can then be transferred; these are then available via a slice in the called function. It is also possible, by appending an ellipse to the last parameter when calling a variadic function, to transfer a slice directly instead of individual parameters. The following is an example analogous to the C # example above.

// Deklariere eine Funktion Sum, die mit beliebig viele Parameter vom Typ int aufgerufen
// wird und die Summe ihrer Parameter zurückgibt.
func Sum(x ...int) (n int) {
    for i := range x { // Iteriere über alle Indizes von x
        n += x[i]
    }

    return
}

// Beispielfunktion zum Aufruf der Funktion Sum()
func ExampleSum() {
    Sum() // leere Summe. Gibt 0 zurück
    Sum(1, 2, 3) // Gibt 6 zurück. x hat den Wert []int{1, 2, 3}
    v := []int{23, 42, 1337}
    Sum(v...) // Wie Sum(23, 42, 1337)
}

Java

The ellipse is also used in the declaration in Java . This is called methods with a variable number of arguments , or Varargs for short . In contrast to C, the type is also specified. In the background, the parameter list is translated into an array , so that the parameter must also be treated like an array within the function body.

JavaScript

In JavaScript , any number of function argumentsarguments are passed to the object, which is an array-like object with the additional properties arguments.lengthand arguments.callee. The argumentsfunction parameters can even be overwritten with the object, as the following example shows:

function meineFunk(x) {
    arguments[0] = 5; // die Variable x wird hier überschrieben!
    ...               // x ist nun 5.
}

Since ECMAScript 2015 it is possible ...to collect function arguments using rest parameters in the form of an ellipse .

function sum(...items) {
    return items.reduce((s, i) => s + i, 0);
}

sum();        // 0
sum(1);       // 1
sum(1, 2, 3); // 6
sum(1, 2, 5); // 8

Lua

In Lua , the ellipse can be ...specified as the last (or only) argument in the parameter declaration of a function. This can then be passed on to other functions, whereby it can be analyzed according to length (number) and individual elements, namely by means of select().

Pearl

Since in Perl 5 the arguments @_end up in the special array regardless of their type , all subroutines are always variadic as long as no prototype explicitly prevents it. The optional signatures introduced with 5.20 check the arity. This means that only those routines are variadic whose last parameter is an array or hash (requires an even number of values).

In Perl 6 you can specify a slurpy array as the last parameter , which is marked with the prefix *and "absorbs" all additional arguments.

PHP

PHP only supports variadic functions from version 4. Up to version 5.5 no special identifier is used in the function declaration; the arguments can be evaluated with the help of special functions. As of version 5.6, variadic functions are available as native language features via the ellipse. In versions prior to 5.6, a variadic function can be defined as follows, for example:

function sum ( /** beliebig viele Argumente **/ ) {
  $result = 0;
  foreach ( func_get_args() as $i ) {
    $result += $i; // hier wird davon ausgegangen, dass alle Parameter vom Typ Integer sind
  }
  return $result;
}

// Beispielhafter Aufruf der Funktion sum()
echo sum(); // gibt 0 aus
echo sum( 1, 2 ); // gibt 3 aus
echo sum( 4, 4, 5, 7 ); // gibt 20 aus

As of PHP 5.6.0, the same function can be implemented as follows:

function sum ( ...$values ) {
  $result = 0;
  foreach ( $values as $i ) {
    $result += $i; // hier wird davon ausgegangen, dass alle Parameter vom Typ Integer sind
  }
  return $result;
}

The output when calling sum()is the same as in the example for versions prior to 5.6.0. The advantage of implementing variadic functions from version 5.6.0 onwards is that so-called type hinting can also be used, which means that there is no need to check for a correctly transferred object type within the function. In the above examples, there is the problem that a user of the function could sum()also transfer a string instead of an integer, which could lead to incorrect output or an exception (if the function expects objects of a certain type). With variadic functions from PHP 5.6.0, the above function can be implemented with type hinting, for example, as follows:

class IntObject {
  private $value;

  public function __construct( $value ) {
    $this->value = $value;
  }

  public function getValue() {
    return $this->value;
  }
}

function sum ( IntObject ...$values ) {
  $result = 0;
  foreach ( $values as $i ) {
    $result += $i->getValue(); // Ein Zugriff auf die Funktion getValue() ist ohne weitere Überprüfung möglich, da PHP bereits überprüft hat, dass alle Werte in $values vom Typ IntObject sind
  }
  return $result;
}

Due to the fact that PHP's type hinting only supports scalar types such as integer or string from version 7.0 , the simple class was IntObjectdefined for this example , which can store a value (which can also be a character string, for example). This example is sufficient for the schematic representation, even if it does not implement type security despite everything.

Ruby

In Ruby , variable numbers of arguments are indicated by an asterisk in front of the parameter name. Again, this parameter is treated as an array in which all arguments are collected that follow the specified number of arguments.

python

Python offers the same functionality as Ruby. In addition, you can name redundant arguments and save their names together with the value in a table (“dictionary” in Python jargon) if parameter names are preceded by two asterisks.

Swift

In Swift , a variable number of parameters is marked with three dots after the declaration of the parameter. Within the function, all transferred values ​​are available as an array:

func summiere(zahlen: Int...) -> Int {

    var sum = 0
    for zahl in zahlen {
        sum += zahl
    }

    return sum
}

Command Language tool

In Tcl , a variable number of parameters is identified with the word argsas the last element of the parameter list. Within the function, all transferred values ​​are available as a list with this name:

proc summiere {args} {
    return [expr [join $args +]]
}
puts [summiere 4 10 8]  ;# gibt 22 aus (ganzzahlig)
puts [summiere 4.5 1 6] ;# gibt 11.5 aus (Fließkommazahl)

Haskell

Haskell does not directly allow the use of variable numbers of arguments, but this can be reproduced almost arbitrarily through the tricky use of type classes. (With a corresponding implementation, for example, type-safe variadic functions with different argument types are also possible).

See also

Individual evidence

  1. ^ Variable argument lists in C. Retrieved September 9, 2010 .
  2. ^ Definition of printf. Retrieved September 9, 2010 .
  3. Ellipses (and why to avoid them). Retrieved September 9, 2010 .
  4. http://en.cppreference.com/w/cpp/language/fold
  5. Params in C #. Retrieved on August 23, 2013 .
  6. Specification of the Go language. Retrieved March 26, 2014 (English).
  7. Varargs in Java. (No longer available online.) Formerly in the original ; accessed on June 10, 2020 .  ( Page no longer available , search in web archives )@1@ 2Template: Dead Link / www.tutego.de
  8. Varargs in Java in the language overview on oracle.com. Retrieved September 1, 2011 .
  9. Variadic functions in PHP. Retrieved September 9, 2010 .
  10. PHP documentation: Function parameters. Retrieved September 8, 2015 .
  11. ^ David Thomas, Andrew Hunt: Programming with Ruby . Addison-Wesley, Munich 2002, ISBN 3-8273-1965-X , p. 281 ( limited preview in Google Book search).
  12. Section Function Definition in the Python Quick Reference. Archived from the original on January 26, 2014 ; accessed on September 9, 2010 (English).
  13. Variadic Parameters: flexible functions in Swift. Retrieved September 13, 2016 .
  14. proc manual page. Retrieved October 6, 2019 .
  15. Implementation in Haskell with a detailed description. Retrieved August 12, 2010 .
  16. Description of the procedure for the Haskell variant of printf for generating a polyvariadic function. Retrieved August 12, 2010 .