Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapter Ids: where to store them? #167

Open
alelom opened this issue Nov 19, 2019 · 11 comments
Open

Adapter Ids: where to store them? #167

alelom opened this issue Nov 19, 2019 · 11 comments
Labels
type:question Ask for further details or start conversation

Comments

@alelom
Copy link
Member

alelom commented Nov 19, 2019

We have 3 options so far.

1) CustomData

As we do now. Dictionary<string, object>.

Pro:

  • It's what we have, no changes needed
  • They are stored in a Dictionary, which is a base C# type
  • Easy to manage

Cons:

  • Arguably CustomData should be left for custom data, not data that is mandatory to have in order for some base BHoM functionality to be working (like the Push). So it's not the proper place for the AdapterId.

2) A Fragment.

Pros:

  • In a certain way, it's more appropriate than CustomData. We do use fragments to specify data that may or may not be required on objects.

Cons:
In a certain way, the AdapterId is not that appropriate as a fragment.

  • We would need to explain the concept of Fragments to every single person coming to implement a new toolkit, even if the only thing they need to do is add an int to an object. This makes Fragment sound inconvenient.

  • If we want to avoid that, we might have an AdaptersIdFragment that actually stores a Dictionary of values, like the CustomData:

    public class AdaptersIdFragment : IBHoMFragment
     {
         public Dictionary<string, object> AdaptersId { get; set; } 
     }

    This comes with a drawback. If you want to add a new Id to the object, you need to:
    - check whether it already has an AdaptersIdFragment
    - if it has, store the value contained in its dictionary
    - add or replace the id in the dictionary
    - replace the dictionary contained in the AdaptersFragment.
    - use bhomObject.AddFragment(adaptersFragment, true) to replace the fragment.
    Since this involves a retrieve operation and quite few steps, it might be a performance hit. Also, it requires a few helper methods.

    We could solve this with an utility method "modifyFragment" to modify the Dictionary stored there. But I'm not sure this is how we want Fragments to be.

    All this to say I'm not sure I find it appropriate as a replacement of the CustomData.
    This is essentially because Fragments are not supposed to be used this way: I think that fragments do not work well with collections of values which are supposed to shrink or expand, like the AdapterId.

3) An additional property of IBHoMObject.

Pros:

  • Easy to implement
  • Arguably, any IBHoMObject can be pushed, so it could make sense to have a property dedicated to its AdapterId

Cons:

  • Not all Adapters need to have the concept of an Adapter_Id.

@al-fisher @rwemay @IsakNaslundBh @adecler @epignatelli

@alelom alelom added the type:question Ask for further details or start conversation label Nov 19, 2019
@IsakNaslundBh
Copy link
Contributor

Would vote for option 2, even if it will be a fragment with just an int for quite a few cases, like:

public GSAId : IAdapterIdFramgent
{
        public int Id { get; set; }
}

and have specific ID fragments for each toolkit. This can then also handle things like Revit, which have more than one ID. ETABS has also more than one way to identify objects which all could be stored in this single fragment. For Revit this is implemented already as a series of CustomData properties, for Etabs nothing is in place yet.

This still means easy lookup both in code and UI. Can scan an object for any IAdapterIdFragment using the method for getting all fragments of a type that you have previously implemented.

For me I would go for something like this, or keep on using CustomData and I think using CustomData really should be phased out for something like this for the reasons you have given above.

As for Option 3, I would not want us to go there for various reasons:

  • An ID from an adapter is not a defining property of an object
  • You then end up with only one number, what if you want to push the element to multiple softwares?
  • Does not solve the Revit/Etabs case of having more than one way of identifying an element
    Could potentially come up with more, but think those reasons are enough for me.

@al-fisher
Copy link
Member

I think @IsakNaslundBh you capture pretty well what I would think on this.

And I do like the idea of a common IFragmentAdapterIDFragment.
Admittedly @alelom you highlight some complexity of the fragments for this use case. I think a common interface - but Toolkit specific fragments goes some way to solving those challenges.
Then what is left I think is reasonable to impose on a Adapter Toolkit Developer. The concept of Fragments can be explained simply again this way. (Not really much more complex than CustomData I feel)

Finally - I am still up for renaming CustomData -> UserData once all remaining use cases left are from human input.

@rwemay
Copy link
Member

rwemay commented Nov 19, 2019

I'd vote option 2 as well, but perhaps do need to do some performance tests before fully implementing? I do think we need a specific dictionary of id's as there will be cases where we need to store multiple as @IsakNaslundBh mentions.

Option 3 could work if it was a dictionary of id's of course, but that's a lot of objects to attach id's to at every stage.

@IsakNaslundBh
Copy link
Contributor

IsakNaslundBh commented Nov 19, 2019

I do think we need a specific dictionary of id's as there will be cases where we need to store multiple as @IsakNaslundBh mentions.

@rwemay for this I would rather have more properties on the ID fragment when needed. For example Revit could end up with something like:

public RevitId : IAdapterIdFramgent
{
        public int Id { get; set; }
        public int ElementId { get; set; }
        public int WorksetId { get; set; }
}

And potentially even add in the family name/type name etc identifiers there (or put them in a separate RevitFamilyFragment ).

Would try to stay away from a dictionary if we can, as one nice thing about putting it in a separate object per toolkit is that we can make everything type-strong and well defined.

For toolkits that mixes ints and strings for ids (like Robot and Etabs) we can always just use the largest common denominator (object/ICompareable/something else), or just use strings.

@al-fisher
Copy link
Member

The beauty of the IAdapterIDFragment approach is you can allow flexibility on the Toolkits to have dictionaries where they need them - or simply ints or guids etc.
Can be flexible. Depends on whether we want or need to impose format on the interface.

In fact you could actually have IIntegerAdapterIDFragment vs
IGUIDAdapterIDFragment etc. If you want to centralise handling of common ID patterns.

On Option 3 - I agree with Isak. I really don’t think it works philosophically for the BHoM.

An ID from an adapter is not a defining property of an object

Think we do need to find a way of optionally storing on objects like the above

@rwemay
Copy link
Member

rwemay commented Nov 19, 2019

@IsakNaslundBh , @al-fisher , sounds very good, and great to have formal properties.

@IsakNaslundBh
Copy link
Contributor

IsakNaslundBh commented Nov 19, 2019

In fact you could actually have IIntegerAdapterIDFragment vs
IGUIDAdapterIDFragment etc. If you want to centralise handling of common ID patterns.

Yes, I like that. Could also make the interface into a generic if we wanted, and if we are sure you will more or less always have a main Id. Like:

public interface IAdapterIdFramgent<T>
{
        public T Id { get; set; }
}

And then have

public GSAId : IAdapterIdFramgent<int>
{
        public int Id { get; set; }
}
public RobotId : IAdapterIdFramgent<string>
{
        public string Id { get; set; }
}

etc.

Not 100% sure on this, if it helps or makes it more complicated, but could generalise comparison of at least main Ids. If the Generics does not feel like a way forward, I like your suggestion as well @al-fisher

@adecler
Copy link
Member

adecler commented Nov 20, 2019

I agree with Isak too. Option 2 seems to be the most reasonable choice.

@alelom
Copy link
Member Author

alelom commented Nov 20, 2019

Good to get agreement on point 2. I will plough on and implement that.

@al-fisher
Copy link
Member

Perfect - thanks @alelom

@IsakNaslundBh
Copy link
Contributor

Putting as a comment here while thinking of it after discussion with @kThorsager .

We have some objects, RigidLink in for multiple softwares and FEMesh for GSA that has a one to many relationship between BHoM and the softwares.

This is, one BHoM RigidLink can turn into multiple of its counterpart in the host software. We have currently solved the ids for those by storing a list of ids on the custom data of the BHoM objects while pushing it.

We need to have a strategy for how to deal with this when we switch to the id fragments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question Ask for further details or start conversation
Projects
None yet
Development

No branches or pull requests

5 participants