Search Unity

Please let a valueTuple can be serialized

Discussion in 'Entity Component System' started by Thaina, Sep 9, 2018.

  1. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,163
    System.ValueTuple can be used in C# 7 from incremental compiler

    Yet it cannot be really used in unity. It cannot be serialized or blittable

    It should be serializable by default like Vector3
     
    TiggyFairy, yong2khoo, Tom980 and 3 others like this.
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,769
  3. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    3,136
    Unity 2018.3 will have C# 7 support. You'll be able to try it later today when we release the beta.
     
    Antypodish and Thaina like this.
  4. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,163
    Now I was using new 2018.3 but the public tuple field was not shown in the inspector UI
     
  5. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,657
    This is expected. C# 7 support means that ValueTuple is now available for use in scripts, but it does not affect the types supported by the Unity serializer.
     
    LeonhardP likes this.
  6. AndrewKaninchen

    AndrewKaninchen

    Joined:
    Oct 30, 2016
    Posts:
    149
    Is there any chance of the Unity serializer supporting more types? I just hit the same wall and it's like the tenth time in 4 days I have to create a workaround because of serialization limitations. SerializeReference coming in 2019.3 is a great addition, but generic serialization would be so good for my nefarious needs.
     
  7. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,163
    Yeah, even the serialize generic is not support. It should support some that so common

    You can serialize
    List<T>
    even it is generic so being generic is not really limitation. So you should at least support
    Tuple
    too
     
  8. Candy_Smith

    Candy_Smith

    Joined:
    May 8, 2014
    Posts:
    102
    Any plans to make Tuple be serializable? It will be very useful.
     
    d1favero likes this.
  9. Leonetienne500

    Leonetienne500

    Joined:
    Dec 5, 2016
    Posts:
    130
    We need serializeable tuples! And unity techonologies will pay for it:D
     
    skabed, wwx317, Metthatron and 7 others like this.
  10. allworknoplay

    allworknoplay

    Joined:
    Mar 5, 2015
    Posts:
    21
    I am also on this bandwagon :p Please let us serialize tuples!
     
    PlayCreatively and n8zach like this.
  11. Compguru910

    Compguru910

    Joined:
    Mar 27, 2013
    Posts:
    4
    Its painful. I just found out after spending an hour coding, that tuples don't work in the inspector.
     
  12. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Sirenix's Odin Inspector will serialize almost everything or show it in the Inspector.
     
  13. ironCookie

    ironCookie

    Joined:
    Sep 3, 2014
    Posts:
    10
    Hey Guys,

    Indeed, serializable tuples would be comfortable. But providing structs is still the better approach. Let me show you why:

    Code (CSharp):
    1. using System;
    2.  
    3. [Serializable]
    4. public abstract class SerializableTuple<T1, T2> : Tuple<T1, T2> {
    5.     [SerializeField]
    6.     private T1 value1;
    7.  
    8.     [SerializeField]
    9.     private T2 value2;
    10.  
    11.     public SerializableTuple(T1 item1, T2 item2): base(item1, item2) {
    12.         value1 = item1;
    13.         value2 = item2;
    14.     }
    15.  
    16.     public new T1 Item1 { get => value1; }
    17.     public new T2 Item2 { get => value2; }
    18. }
    19.  
    20. [Serializable]
    21. public class IntFloatTuple : SerializableTuple<int, float>
    22. {
    23.     public IntFloatTuple(int item1, float item2) : base(item1, item2){ }
    24. }
    When working carefully with namespaces, one could also write something like this:

    Code (CSharp):
    1. public abstract class Tuple<T1, T2> : System.Tuple<T1, T2> {
    2.   /*...*/
    3. }
    The problem of this serializable tuple is, of course, the overhead! As you can see, item1 and item2 must still be passed into the base class. By defining two additional fields and using the "new" keyword, one can hide the data and the properties of the base class, resulting in consuming more memory.

    I havent tested the Odin Inspector yet, but I think your best bet to expose tuples within the Unity inspector would be by creating CustomPropertyDrawers! Or by sticking to use custom structs.
     
    art500 likes this.
  14. ironCookie

    ironCookie

    Joined:
    Sep 3, 2014
    Posts:
    10
    For the sake of completeness, I have prepared a sample class for those of you, who need a class with the same functionality as the System.Tuple class.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3.  
    4. namespace MyCustomNamespace
    5. {
    6.     [Serializable]
    7.     public class Tuple<T1, T2> : IStructuralComparable, IStructuralEquatable, IComparable
    8.     {
    9.         [SerializeField]
    10.         private T1 item1;
    11.  
    12.         [SerializeField]
    13.         private T2 item2;
    14.  
    15.         public T1 Item1 => item1;
    16.         public T2 Item2 => item2;
    17.  
    18.         public Tuple(T1 item1, T2 item2)
    19.         {
    20.             this.item1 = item1;
    21.             this.item2 = item2;
    22.         }
    23.  
    24.         public int CompareTo(object other, IComparer comparer)
    25.         {
    26.             throw new NotImplementedException(); // TODO
    27.         }
    28.  
    29.         public int CompareTo(object obj)
    30.         {
    31.             throw new NotImplementedException(); // TODO
    32.         }
    33.  
    34.         public bool Equals(object other, IEqualityComparer comparer)
    35.         {
    36.             throw new NotImplementedException(); // TODO
    37.         }
    38.  
    39.         public int GetHashCode(IEqualityComparer comparer)
    40.         {
    41.             throw new NotImplementedException(); // TODO
    42.         }
    43.     }
    44.  
    45.     [Serializable]
    46.     public class IntDoubleTuple : Tuple<int, double> {
    47.         public IntDoubleTuple(int item1, double item2) : base(item1, item2) { }
    48.     }
    49. }
     
  15. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,163
    @ironCookie When we talk about `Tuple` we mostly means `ValueTuple` that was linked to C# syntax

    Code (CSharp):
    1.  
    2. (int left,int right) pair = (0,0);
    3.  
    4. pair.left = 1;
    5. pair.right = 1;
    6.  
    So it is struct and do not have the same behaviour as a class one and your argument don't fully apply to it
     
  16. ironCookie

    ironCookie

    Joined:
    Sep 3, 2014
    Posts:
    10
    @Thaina
    Oh, my bad. I thought the thread has only started discussing ValueTuples, but would have ended discussing ordinary .Net 4 Tuples.

    --------------

    Probably, I still do not have read enough articles about serializing ValueTuples. But it seems that one major problem is the absence of named elements in the compiled source, which makes the serialization as well as the use of reflections a little bit more tricky.

    Anyway, I would like to present one more code snippet, before I keep my mouth shut. Please let me know, what you are thinking about this approach.

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3.  
    4. [Serializable]
    5. struct Wrapper
    6. {
    7.     public int _left;
    8.     public int _right;
    9.     private Wrapper((int left, int right) pair)
    10.     {
    11.         _left = pair.left;
    12.         _right = pair.right;
    13.     }
    14.  
    15.     public static implicit operator Wrapper((int left, int right) pair)
    16.     {
    17.         return new Wrapper(pair);
    18.     }
    19. }
    Use it like this:

    Code (CSharp):
    1. [SerializeField]
    2. private Wrapper pair = (0,4);
     
  17. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,163
    @ironCookie Yeah, still not the point

    The valuetuple serializer don't really need to be named. It could name by internal `Item1` `Item2` `ItemN`

    And the point of using tuple is so that we don't need to create specific struct that just a combination of other struct. We might need to use `int,float` `float,int` `float,long` `long,int,float,string` and any combination without the need to unnecessary create actual struct type and pollute our code base, kept struct to be only object that need to be specific type
     
  18. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    226
    +1. Unity needs to put some effort into furthering serialization support. Tuple, guid, dictionary to name a few. I am tired of implementing ISerializationCallbackReceiver in so many of my classes.

    A nice aspect of serialization support is reloading scripts and staying in playmode for quick iteration, testing, and prototyping.

    As far as using struct, oy vey, let's stay on topic. Talking about struct seems to basically be questioning the point of tuple.
     
    NeatWolf, TWolfram, Thygrrr and 4 others like this.
  19. Kmsxkuse

    Kmsxkuse

    Joined:
    Feb 15, 2019
    Posts:
    306
    No serialization but at least it can be bursted (inside a job) as of 1.5.
     
  20. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,163
    As of dotnet progress, tuple are all around as simple compact datastructure. Why unity still don't try to really support it
     
  21. marcospgp

    marcospgp

    Joined:
    Jun 11, 2018
    Posts:
    194
    Consider having specialized classes such as this
    SerializableDictionary
    :

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. namespace MarcosPereira.UnityUtilities {
    7.     // This class is serializable but not a ScriptableObject, as Unity does not
    8.     // support generic ScriptableObjects.
    9.     // Keep in mind that custom classes have poorer serialization support.
    10.     // For example, shared references may become independent copies.
    11.     [Serializable]
    12.     public class SerializableDictionary<K, V> :
    13.     ISerializationCallbackReceiver, IEnumerable<KeyValuePair<K, V>> {
    14.         private readonly Dictionary<K, V> dictionary = new Dictionary<K, V>();
    15.  
    16.         [SerializeField]
    17.         private List<K> serializableKeys;
    18.  
    19.         [SerializeField]
    20.         private List<V> serializableValues;
    21.  
    22.         void ISerializationCallbackReceiver.OnBeforeSerialize() {
    23.             this.serializableKeys = new List<K>(this.dictionary.Keys);
    24.             this.serializableValues = new List<V>(this.dictionary.Values);
    25.         }
    26.  
    27.         void ISerializationCallbackReceiver.OnAfterDeserialize() {
    28.             this.dictionary.Clear();
    29.  
    30.             for (int i = 0; i < this.serializableKeys.Count; i++) {
    31.                 this.dictionary.Add(
    32.                     this.serializableKeys[i],
    33.                     this.serializableValues[i]
    34.                 );
    35.             }
    36.         }
    37.  
    38.         // Allow iterating over this class
    39.         IEnumerator<KeyValuePair<K, V>> IEnumerable<KeyValuePair<K, V>>.GetEnumerator() =>
    40.             this.dictionary.GetEnumerator();
    41.  
    42.         IEnumerator IEnumerable.GetEnumerator() =>
    43.             this.dictionary.GetEnumerator();
    44.  
    45.         public V this[K key] {
    46.             get => this.dictionary[key];
    47.             set => this.dictionary[key] = value;
    48.         }
    49.  
    50.         public int count => this.dictionary.Count;
    51.  
    52.         public Dictionary<K, V>.KeyCollection keys => this.dictionary.Keys;
    53.         public Dictionary<K, V>.ValueCollection values =>
    54.             this.dictionary.Values;
    55.  
    56.         public void Add(K key, V value) => this.dictionary.Add(key, value);
    57.  
    58.         public bool Remove(K key) => this.dictionary.Remove(key);
    59.  
    60.         public bool TryGetValue(K key, out V value) =>
    61.             this.dictionary.TryGetValue(key, out value);
    62.     }
    63. }
    64.  
     
    Last edited: Sep 21, 2022
    tonytopper likes this.
  22. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    39
    It's been over 5 years since this was posted and tuples still can't be serialized
     
  23. stevphie123

    stevphie123

    Joined:
    Mar 24, 2021
    Posts:
    82
    I can see why the idea of serializing valuetuple is actually a terrible idea.

    Imagine a dumbo coder would do this `((int, float), (double (string, string)))`
    look at that ctulhu monster lmao
     
  24. apkdev

    apkdev

    Joined:
    Dec 12, 2015
    Posts:
    283
    To be fair, that's not an argument against serializing tuples, but against abusing tuples.
     
    Thaina likes this.