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

Reworked RDFEntity interface and added SemanticEntity #37

Merged
merged 14 commits into from
Aug 8, 2018

Conversation

niniemann
Copy link
Collaborator

This PR implements two major changes which build upon each other:

  1. The RDFEntity has essentially been renamed to RDFVector. The RDFEntity-Class still exists, but is only used as an interface to containers of rdf triples. Every RDFEntity must be iterable, but can provide its own implementation of the iterator. Using this I also simplified the RDFPropertyMap, which had a really messed up structure as it had to store everything twice -- once in a map, once in the RDFEntitys triple-vector. Now the RDFPropertyMap only stores a map and constructs the triples on demand.
  2. I implemented the SemanticEntity-class, which follows a completely different approach to provide RDF triples to the data: You can register member variables to make them directly visible, which allows you to use them as usual (type safety etc), without any casting involved. See the updated README for more information.

Of course there are still some limitations. One of them is the fact that you need to derive from SemanticEntity to make use of its features... This may be improved in the future.

Oh, and I'm also not quite satisfied with the RDFEntity-iterator-stuff. Both the RDFPropertyMap and the SemanticEntity do not store any actual Triples , but the iterator constructs them on demand, without storing them. I use a static variable in the iterators dereference-operator for that, but that means that the returned const Triple& is not really const! As soon as the iterator is incremented and dereferenced again, the static local variable changes its value... And when the iterator goes out of scope? 🙁

So, be careful with that, I haven't really figured out how to do this properly. Any ideas?
(Take a look at this part of the code to see what I mean).

@niniemann
Copy link
Collaborator Author

By the way, although this implementation differs from what I proposed previously, it fixes #31. The overhaul of RDFPropertyMap has removed the need for the workaround when deleting entries, and the SemanticEntity is the static alternative.

@ctieben ctieben self-requested a review August 6, 2018 07:07
Copy link
Contributor

@ctieben ctieben left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First review comments.


Internally, for every registered property an instance of `RegisteredPropertyBase` is stored in a vector of the SemanticEntity. Those objects simply provide an interface to `virtual std::string object() const = 0;` which is provided by the (templated) derived classes `RegisteredProperty`. The `RegisteredProperty`s in turn have to major modifications:

1. They also provide a `bool isValid() const;` which is implemented differently for `std::shared_ptr`, in which case they return if the property/variable/member is not null. In case of non-shared-ptrs it always returns true. This method is used to check if a registered property should be skipped on iteration, as a nullptr is (IMHO) best represented by the absence of a triple.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect such a details description as code documentation not as general in the readme.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is well-documented, of course :D. Everything you read here is described in code-comments, too -- this is just a more structured explanation of how stuff works internally that can be read in one go.

Also, it is written beneath the header "Implementation details", so IMHO this is totally fine. 😉

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

class TripleIterator_impl {
friend class TripleIterator;
protected:
virtual ~TripleIterator_impl();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange naming with *_impl and it implements nothing its just an interface.
Also the child's are named in this way :-(

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that I want to return an iterator by value, and not a pointer to an iterator that points to some triples. The latter would force the user to write stuff like
(**it).subject; or *(*it)->subject and to delete the iterator in the end. If I'd just return a FooIterator, but the method signature in the RDFEntity class specifies a TripleIterator, the result would be a TripleIterator created from a FooIterator... not what I wanted. So my solution is to give the TripleIterator class a pointer to the actual implementation which has to be provided by the entity types that are RDF-iterable. The TripleIterator_impl is the interface for this implementation, which we need for the TripleIterator to work correctly (virtual methods...).

I agree that the naming of the actual implementations [...]_impl is a bit weird, but it simply follows the pattern. Do you have any suggestion how to improve this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case I think the TripleIterator shall be renamed because its an abstract wrapper for the real iterators. It could be renamed to something like AbstractTripleIterator or TripleIteratorWrapper after these step the *_impl could be removed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I'm on it.

namespace sempr {

namespace rdf {
namespace traits {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there no better place to define the rdf traits?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. Any suggestions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mhhh it could be moved to a Utils or Traits Header in a (not existing) rdf subdir.

In general all the RDF specific entities could be moved in a entity/rdf subdir. What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle: Yes. But this leads to changes in everything that uses sempr, again... Maybe postpone it until we do a complete overhaul of the structure? I'm not really happy with the overall setup of directories and namespaces...

For now I'm fine with those traits being defined in the SemanticEntity.hpp, since only the SemanticEntity uses them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok for now its fine.


const Triple& RDFPropertyMapIterator_impl::operator*() const
{
static Triple t;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why static?
t is changed by every call. It also could be non static and non reference to get a copy of the created object.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because then the operator ->() const wouldn't work anymore.


const Triple* RDFPropertyMapIterator_impl::operator->() const
{
return &(**this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And now it gets dirty. You will always return the address to the static local variable with this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works. And it's a static variable. So what? ;D
I agree that this is a bit ugly. Maybe I was way too focused on creating an iterator that I favored the signatures over sensible implementation.

@niniemann
Copy link
Collaborator Author

I've updated the TripleIterator to return triples by value instead of reference. I'm still open for naming-suggestions, but wouldn't mind to leave it as it is. 😉

Copy link
Contributor

@ctieben ctieben left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have only found some out commeted stuff in a second review.

{
}

// std::vector<Triple>::const_iterator RDFVector::begin() const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this begin() and end() be removed? (also in the header file)

// RDFProperty<std::string> stringValue_;
// RDFProperty<Person::Ptr> entityValue_;

// TODO test composite value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still like to test it? :-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Composite values are... not so straight forward. I'll leave this for a future extension, just like vectors. So the answer is: No. ^^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will you create a issue for this topic?

Copy link
Contributor

@ctieben ctieben left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a small thing in the 'TripleIteratorWrapper'.

{
return triples_.begin();
if (!impl_)
throw std::exception();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't you trust yourself?
The impl_ point could be stored as const in the wrapper and the c'tor can check the null expr.
These functions could also be declared as inline (in a future release).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... the TripleIteratorWrapper relies on the user providing him with a valid implementation. I don't know, it just felt right to check if I actually set it. Though this is probably a bit exaggerated... What do you want me to change? Just get rid of it? Or leave it as it is? Or do the check in the c'tor to fail more early?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea is to const the pointer and to have only one check in the c'tor. All other methods can than expect that the pointer is valid.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this? 4a6d8e4

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@niniemann niniemann merged commit 958d77d into master Aug 8, 2018
@niniemann niniemann deleted the rdfentity-interface branch October 1, 2018 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants