Tuple w C#7 vs F# vs TypeScript

Czas czytania ~ 200 sekund

Co zrobić, by funkcja mogła zwracać wiele wartości ? Można opakować te wartości w klasę lub strukturę.  W poprzednich wersjach C# mieliśmy także do dyspozycji generyczne klasy Tuple, które wystawiały propertiesy Item1, Item2, …. ItemN.  Innymi, również niezbyt wygodnymi sposobami na przekazywanie kilku wartości jako wyjścia z funkcji były na przykład parametry ze słowem kluczowym out, czy typy anonimowe opakowywane w słowo kluczowe dynamic. Wydaje się, że w nowym C# w wersji 7 mamy w końcu bardzo wygodny sposób na rozwiązanie tego problemu. Są nim nowe Tuple.

Na początku jednak zobaczmy, jak z krotek korzysta się w F# i TypeScript.

F#

let getString = fun () -> ("Hello Tuples", 11)

[<EntryPoint>]
let main argv =

    let result = getString()
    let str = fst result
    let (text, length) = getString()

    printfn "%A" str
    0 // return an integer exit code

Mamy funkcję, której sygnatura wygląda tak: unit -> string * int, a więc nie przyjmuje nic, a zwraca krotkę, której typy są oddzielane w F# gwiazdką. Samo wywołanie takiej funkcji przypisze do zmiennej result właśnie taką krotkę. Mamy także dwa specjalne operatory wbudowane w język: fst oraz snd, którymi możemy pobierać pierwszą i drugą wartość krotki. Dodatkowo dostępny jest destructuring, czyli możliwość przypisania krotki do nazwanych zmiennych.

TypeScript

function getString() : [string, number]{
    return ["Hello Tuples", 11];
}

let myTuple = getString();
// myTuple = ["Some string", "Trying to use another string instead of number"];
console.log(myTuple[0]);

W TypeScript krotki oznaczamy kwadratowymi nawiasami. Stworzenie takiej tablicy jest możliwe również w samym JS. Tym, co wnosi tutaj TypeScript jest silne typowanie i jeżeli spróbujemy odkomentować przedostatnią linię, dostaniemy błąd kompilatora:

main.ts(7,1): error TS2322: Type ‘[string, string]’ is not assignable to type ‘[string, number]’.
Types of property ‘1’ are incompatible.
Type ‘string’ is not assignable to type ‘number’.

C# 7.0

Po zainstalowaniu Visual Studio i założeniu aplikacji dot-netowej, aby skorzystać z tupli musimy jeszcze doinstalować NuGet z ValueTuple

Przechwytywanie2

Dostarcza on generyczne struktury ValueTuple, do których kompilator tłumaczy takie oto zapisy:

static void Main(string[] args)
{
    var result = GetString();
    Console.WriteLine(result.str);

    Tuple<string,int> oldTuple = result.ToTuple();
    Console.ReadKey();
    Console.WriteLine(oldTuple.Item1);

    //destructuring
    (string resultStr, _) = GetString();
    Console.WriteLine(resultStr);
}

static (string str, int length) GetString()
{
    return ("Hello Tuples", 12);
}

A więc możemy zwracać nazwane pary wartości. Dodatkowo ValueTuple dostarcza metodę ToTuple, która pozwala na konwersję nowych ValueTuple do starych generycznych Tuple. Wraz z tuplami mamy możliwość znanego chociażby z nowego JS-a destructuringu – wynik będący krotką przypisujemy do nazwanych zmiennych, możemy też niektóre z nich pomijać (znak underscore w przykładzie powyżej).

A co po dekompilacji dotPeekiem ?

internal class Program
{
  private static void Main(string[] args)
  {
    ValueTuple<string, int> valueTuple = Program.GetString();
    Console.WriteLine(valueTuple.Item1);
    Tuple<string, int> tuple = valueTuple.ToTuple<string, int>();
    Console.ReadKey();
    Console.WriteLine(tuple.Item1);
    //....
  }

  [return: TupleElementNames(new string[] {"str", "length"})]
  private static ValueTuple<string, int> GetString()
  {
    return new ValueTuple<string, int>("Hello Tuples", 12);
  }
}

Nazwy elementów krotki kompilowane są jako parametry atrybutu, kompilator dodaje także od siebie opakowanie zwracanej wartości w ValueTuple. Dzięki temu mamy bardziej zwięzły i czytelny kod.

Advertisements

One thought on “Tuple w C#7 vs F# vs TypeScript

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s