Search Unity

Why ScriptableObject.CreateInstance instead of constructor?

Discussion in 'Editor & General Support' started by kiriri, Sep 23, 2015.

  1. kiriri

    kiriri

    Joined:
    Jan 14, 2011
    Posts:
    107
    Hey,
    I've been working on a project where I needed Editor serialization. Therefore I opted to inherit most classes from ScriptableObject. As always I started off with the Editor console warnings suppressed. I've been using custom constructors with my classes for months now, without any issues, but I just noticed that I've been getting a new warning each time I use my constructors :

    where TYPE is the type that inherits form ScriptableObject.
    This is confusing. As I mentioned, I had absolutely no problems doing it this way, the only thing that made me notice the warnings was the framerate due to the ridiculous amount of console warnings.
    Is this warning deprecated? Has anyone encountered cases where the extra CreateInstance function did anything useful? Can I just suppress it via pragma and forget about it alltogether?

    Edit : Just realized it can't be suppressed since it doesn't have an ID...
     
    Last edited: Sep 23, 2015
  2. RockoDyne

    RockoDyne

    Joined:
    Apr 10, 2014
    Posts:
    2,234
    The point of scriptable objects is mostly so you can serialize data in the editor. As far as I'm aware, you don't want to be using constructors because that is likely to get in the way when Unity should be serializing the data.
     
  3. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    The way to create ScriptableObjects is by using CreateInstance. Internally, Unity invokes the constructor for these types, but it may do so multiple times, or in whatever way it likes to.

    You should always create new instances of ScriptableObjects using CreateInstance.

    BTW: ScriptableObjects are used for more than just "editor serialization"... actually most people use them at runtime to store different values.
     
    sama-van likes this.
  4. RockoDyne

    RockoDyne

    Joined:
    Apr 10, 2014
    Posts:
    2,234
    They don't need to be scriptable objects at that point though. You can use any kind of class if you just want to store data at runtime or in an xml/json/binary file for persistence. What makes scriptable objects special is that the editor knows how to handle them, and outside of that use case, they aren't particularly valuable.
     
  5. kiriri

    kiriri

    Joined:
    Jan 14, 2011
    Posts:
    107
    This is (no longer?) always the case. In my case it doesn't interfere at all.

    That would be the parameterless constructor wouldn't it ? I think that explains the warning then. All other constructors call the parameterless constructor afterall, and that one should never be overwritten or else it will mess with the serialization. So Unity put in a warning in the parameterless ScriptableObject constructor to remind us to never use, and in extension to never overwrite the parameterless constructor. (constructors can't be sealed)
    It's just a pity we can't suppress the warning because creating and using overloaded constructors is no problem at all.
     
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Its called the factory pattern. The class owns a static method that is intended to be used instead of a constructor. You can probably do some google searches on why this pattern exists. Its a good chance the general reasons for the pattern are the same as why Unity choose to use it.

    The most likely reason I can think of is that the ScriptableObject constructor does something special. And Unity devs didn't want to rely on users calling the base constructor inside the inherited classes constructor.

    Are you sure? Seems relatively pointless to me. At runtime you can just create a regular class. The main draw of ScriptableObjects is their persistence and their editor friendliness.
     
  7. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Let me rephrase: what was written above was that "The point of scriptable objects is mostly so you can serialize data in the editor". This implies that you can use them only for saving things that you're working on in the editor (and will not be used at runtime).
    I meant that the data you're serializing can also be used at runtime.

    ScriptableObjects are nicer than just using plain serializable classes or any other data serialization format, in that indeed the editor plays nicely with them - you automatically get an inspector for them once they're saved as assets in the project, and you can drag/drop other objects into their public fields.
     
    Walter_Hulsebos and SunnyChow like this.
  8. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    945
    I think the most important part about ScriptableObjects is that they retain their type after deserialization (Unity's built in serialization is broken for polymorphism of custom classes - you end up with an instance of the base type).
     
    Walter_Hulsebos and NeonTheCoder like this.
  9. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,572
    You shouldn't blindly inherit everything from scriptable objects.
    You also shouldn't ever blindly do anything while programming.

    If you need serialization, it will work on plain classes just fine. (mark classes as System.Serializable)

    The point of scriptable object is that multiple objects can reference one scriptable object instance AND those references will be correctly serialized (if you do that with plain classes, you'll get duplicates on deseralization). The references can be assigned by drag and drop.

    Most of the time, you don't need that kind of thing.

    I mostly use scriptable objects for configuration "files" that can sit within project and can be quickly referenced from elsewhere. They're pretty much only useful as configuration files - you can achieve the rest of functionality using GameObjects, Transforms and by referencing individual components.
     
    andywatts and levlaj like this.
  10. pointcache

    pointcache

    Joined:
    Sep 22, 2012
    Posts:
    579
    A constructor of so
    Code (CSharp):
    1.     public ScriptableObject()
    2.     {
    3.         CreateScriptableObject(this);
    4.     }
    Guess the warning is some legacy stuff.
     
  11. You really shouldn't call the constructor on any Unity.Object. It's because Unity's objects are living in two worlds at once:
    - in the managed side, what you're doing, and they are normal C# objects
    - in the C++ side, where the Unity engine takes care of the data in order to be able to work with them on the native side

    If you're calling the constructor yourself, you're only creating the managed side, you will introduce all sorts of problems for yourself.

    It is not legacy stuff.
     
    Kiwasi likes this.
  12. pointcache

    pointcache

    Joined:
    Sep 22, 2012
    Posts:
    579
    Both CreateInstance and constructor make calls to the native side, the only difference is that constructor first creates managed instance and then passes it to the native side for processing.

    https://github.com/Unity-Technologi...0/Runtime/Export/ScriptableObject.bindings.cs

    Both make call to the same native method, but different overload.
     
  13. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    945
    From the c# source you posted, this seems to be just an assumption. You don't know what else these methods do on the native side if you don't own the source code. And i suspect them to not do the same thing, but internally need to be called in order, but that's also just an assumption.