Abilitare JavaScript per vedere questo sito.

Dichiarazione di funzione

Riferimenti ai parametri

Riferimenti al ritorno

Sovraccarico delle funzioni

Argomenti predefiniti

Funzioni anonime

Le funzioni sono dichiarate globalmente e consistono in una firma in cui vengono definiti i tipi di argomenti e il valore di ritorno e in un corpo in cui viene dichiarata l'implementazione.

Dichiarazione di funzione

Le funzioni globali forniscono il mezzo per implementare routine che devono operare su alcuni input e produrre un risultato. Le funzioni stesse non mantengono alcuna memoria, anche se possono aggiornare variabili globali o memoria passata per riferimento.

La funzione viene sempre dichiarata insieme al corpo della funzione. Non è necessario dichiarare i prototipi di funzione, poiché la funzione è visibile a livello globale, indipendentemente da dove è stata dichiarata.

// A simple function declaration
int AFunction(int a, int b)
{
  // Implement the function logic here
  return a + b;
}

Il tipo del valore di ritorno deve essere specificato prima del nome della funzione. Se la funzione non restituisce nulla, il tipo deve essere definito come "void". Dopo il nome della funzione, si specifica l'elenco dei parametri tra parentesi. Ogni parametro è definito dal suo tipo e dal suo nome.

Riferimenti ai parametri

I parametri e il valore di ritorno possono essere di qualsiasi tipo, utilizzabile anche per le dichiarazioni di variabili. Inoltre, è possibile fare in modo che una funzione assuma un valore per riferimento, ossia che il parametro non sia una copia del valore originale, ma faccia riferimento al valore.

I riferimenti ai parametri sono utilizzati principalmente per due scopi: un mezzo per fornire un output aggiuntivo dalla funzione, o come un modo più performante di passare i valori.

In script avanzato è necessario specificare l'intenzione del riferimento al parametro, cioè se è inteso come input, output o entrambi. Questo è necessario affinché il compilatore prepari il riferimento in modo che non possa essere invalidato a causa di qualche azione durante l'elaborazione della funzione.

I riferimenti di ingresso sono scritti come &in. Poiché il riferimento è inteso solo come input, il valore effettivo a cui si riferisce è normalmente una copia dell'originale, in modo che la funzione non modifichi accidentalmente il valore originale. Questi riferimenti non sono comunemente utilizzati, in quanto forniscono pochi vantaggi rispetto al passaggio degli argomenti per valore. Solo in alcune circostanze è possibile migliorare le prestazioni, soprattutto se il parametro è dichiarato anche come const.

I riferimenti all'uscita sono scritti come &out. Questi riferimenti hanno lo scopo di consentire alla funzione di restituire valori aggiuntivi. Quando si entra nella funzione, il riferimento punta a un valore non inizializzato. Dopo il ritorno della funzione, il valore assegnato dalla funzione verrà copiato nella destinazione determinata dal chiamante.

Quando il riferimento è inteso sia come ingresso che come uscita, viene dichiarato come &inout, o semplicemente &. In questo caso il riferimento punta al valore effettivo. Solo i tipi di riferimento, cioè quelli che possono avere degli handle, possono essere passati come riferimenti inout. Questo perché, per garantire che il riferimento rimanga valido durante l'intera esecuzione della funzione, il valore deve trovarsi nell'heap della memoria.

void Function(const int &in a, int &out b, Object &c)
{
  // Assigning an output value to the output reference
  b = a;
  // The object is an inout reference and refers to the real object
  c.DoSomething();
}

Riferimenti al ritorno

Una funzione può anche restituire dei riferimenti, che permetteranno al chiamante di modificare il valore puntato dal riferimento. Per dichiarare una funzione che restituisce un riferimento, includere il simbolo & tra il tipo di ritorno e il nome della funzione. Aggiungere const prima del tipo se il riferimento deve essere di sola lettura, cioè se non deve essere possibile modificare il valore a cui punta.

int property;
int &Function()
{
  // Return a reference to the property
  return property;
}
void main()
{
  // Modify the value pointed to by the returned reference
  Function() = 1;
}

La necessità di garantire che il riferimento sia valido anche dopo la restituzione della funzione al chiamante comporta alcune restrizioni. Non è necessario cercare di ricordare queste restrizioni, poiché il compilatore darà un errore se vengono violate, ma se si verifica un errore di compilazione quando viene restituito un riferimento, è bene capire perché si verifica, in modo da poter determinare come evitarlo.

I riferimenti alle variabili globali sono consentiti

Poiché una variabile globale si trova nell'ambito globale, la vita della variabile è più lunga dell'ambito della funzione. Una funzione può quindi restituire un riferimento a una variabile globale, o anche a un membro di un oggetto raggiungibile attraverso una variabile globale.

I riferimenti ai membri della classe sono consentiti

Un metodo di classe può restituire un riferimento a una proprietà della classe dello stesso oggetto; poiché il chiamante è tenuto a mantenere un riferimento all'oggetto, è noto che il membro esisterà anche dopo il ritorno del metodo.

Il metodo di classe può anche restituire riferimenti a variabili globali, come qualsiasi altra funzione.

Non è possibile restituire riferimenti a variabili locali

Poiché le variabili locali devono essere liberate quando la funzione esce, non è consentito restituire un riferimento ad esse. Lo stesso vale per i parametri ricevuti dalla funzione. Anche i parametri vengono ripuliti all'uscita della funzione, quindi non possono essere restituiti come riferimento.

Non si possono usare espressioni con parametri differiti

Per alcune chiamate di funzione con argomenti, potrebbe essere necessaria un'elaborazione degli argomenti dopo il ritorno della chiamata di funzione, ad esempio per ripulire l'oggetto di input o per assegnare i parametri di output. Se la funzione chiamata restituisce un riferimento, questo non può essere restituito a sua volta, perché potrebbe essere invalidato dalla valutazione differita degli argomenti.

Non si possono utilizzare espressioni che si basano su oggetti locali

Tutti gli oggetti locali devono essere ripuliti prima dell'uscita di una funzione. Per le funzioni che restituiscono riferimenti, questa pulizia avviene prima che venga valutata l'espressione di ritorno, altrimenti la pulizia degli oggetti locali potrebbe invalidare accidentalmente il riferimento. Per questo motivo non è possibile utilizzare espressioni che si basano su oggetti locali per valutare il riferimento da restituire.

È invece possibile utilizzare valori primitivi, che non richiedono la pulizia all'uscita.

Sovraccarico delle funzioni

L'overloading delle funzioni avviene quando più funzioni con lo stesso nome vengono dichiarate con parametri diversi. Si tratta di una caratteristica utile quando un'operazione deve essere in grado di lavorare con diversi tipi di input, pur producendo risultati simili.

Il compilatore è in grado di decidere quale funzione chiamare facendo corrispondere il tipo di ogni espressione dell'argomento al parametro della funzione ed eliminando le funzioni per le quali non è disponibile una conversione. Il compilatore esegue questa operazione per ogni argomento, dal primo all'ultimo. Quando tutti gli argomenti sono stati valutati, solo una funzione dovrebbe essere la migliore, altrimenti il compilatore darà un errore sull'impossibilità di determinare la funzione corretta da chiamare.

Il tipo di conversione che deve essere eseguita sull'argomento per ottenere il tipo del parametro determina la corrispondenza di una funzione. L'elenco seguente indica l'ordine di conversione di un tipo rispetto a un altro.

nessuna conversione necessaria

conversione in const

conversione di un enum in un intero della stessa dimensione

conversione di enum in intero di dimensione diversa

la dimensione del tipo primitivo aumenta

la dimensione del tipo primitivo diminuisce

conversione da intero firmato a intero non firmato

conversione da intero senza segno a intero firmato

conversione da tipo intero a tipo float

conversione da tipo float a tipo intero

cast di riferimento

conversione da oggetto a primitiva

conversione in oggetto

tipo di argomento variabile

Si noti che non è possibile creare sovraccarichi in cui l'unica differenza sia il tipo di ritorno. Questo perché il tipo di ritorno non fa parte dei criteri di selezione che il compilatore utilizza per determinare quale funzione chiamare; il tipo di ritorno è solo il risultato della funzione chiamata.

void Function(int a, float b, string c) {}
void Function(string a, int b, float c) {}
void Function(float a, string b, int c) {}
void main()
{
  Function(1, 2.5f, 'a');  // Will call the first overload
  Function('a', 1, 2.5f);  // Will call the second overload
  Function(2.5f, 'a', 1);  // Will call the third overload

Argomenti predefiniti

A volte l'implementazione di funzioni diverse per ogni sovraccarico non è necessaria quando la differenza può essere fornita con un valore predefinito di un parametro. È qui che gli argomenti predefiniti si rivelano utili.

Definendo gli argomenti predefiniti nella dichiarazione della funzione, lo script non deve fornire questi valori in modo specifico quando chiama la funzione, poiché il compilatore inserisce automaticamente gli argomenti predefiniti.

void Function(int a, int b = 1, string c = "")
{
  // Inside the function the arguments work normally
}
void main()
{
  // Default arguments doesn't have to be informed
  // The following three calls produce the exact same result
  Function(0);
  Function(0, 1);
  Function(0, 1, "");
}

Quando si definisce un argomento predefinito per uno dei parametri, anche tutti i parametri successivi devono avere un argomento predefinito.

L'espressione dell'argomento predefinito può includere riferimenti a variabili o funzioni, ma solo se le variabili o le funzioni sono visibili nell'ambito globale.

int myvar = 42;
void Function(int a, int b = myvar) {}
void main()
{
  int myvar = 1;
  Function(1);    // This will use the global myvar and not the local myvar
}

L'espressione speciale 'void' può essere utilizzata come argomento predefinito per creare un parametro di uscita opzionale.

void func(int &out output = void) { output = 42; }

Funzioni anonime

Le funzioni anonime, o lambda come vengono talvolta chiamate, sono funzioni dichiarate localmente per essere utilizzate con gli handle delle funzioni.

Di seguito viene fornita una rapida dimostrazione di come utilizzare le funzioni anonime.

funcdef bool CMP(int first, int second);
void main()
{
  int valueA = 1, valueB = 2;
  bool result1 = func(valueA, valueB, function(a,b) { return a == b; });
  bool result2 = func(valueA, valueB, function(a,b) { return a != b; });
}
bool func(int a, int b, CMP @f)
{
  return f(a,b);
}

La funzione anonima assume la firma dell'handle della funzione a cui è assegnata, quindi il tipo degli argomenti e il tipo di ritorno non devono essere dichiarati esplicitamente.

Le funzioni anonime non possono ancora accedere a variabili dichiarate nello stesso ambito della funzione, cioè non possono essere usate come chiusure.

Se ci sono più usi corrispondenti per la funzione anonima, sarà necessario informare esplicitamente i tipi di parametri, in modo da risolvere l'ambiguità.

funcdef void A(int);
funcdef void B(float);
void func(A@) {}
void func(B@) {}

void main()
{
  // Explicitly specify the type to tell the compiler that A is wanted
  func(function(int a) {});
}

 

  

Keyboard Navigation

F7 for caret browsing
Hold ALT and press letter

This Info: ALT+q
Page Header: ALT+h
Topic Header: ALT+t
Topic Body: ALT+b
Contents: ALT+c
Search: ALT+s
Exit Menu/Up: ESC