Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
For #94, @danielhuppmann asked in the
core
layer: "Why doesParameter
not inherit fromTable
"? And sure enough, these optimization items share a lot of common functionality. So before moving on toVariable
andEquation
, for which this will be the case even more so, I wanted to take another look at this.@meksor, I expect you'll be the one to take a look at this. Sorry, this description might be a bit lengthy.
Initially, I interpreted the question as for the DB layer, and how to handle inheritance (or rather Composition) there has been recently discussed in #82. Instead, this PR focuses on the core layer, where we also have two classes per optimization item that could potentially benefit from higher reusability (to follow the DRY principle): e.g., the
Table
(mostly a collection of data attributes) and theTableRespository
(functions to handleTable
s).For the
Table
s themselves (and similar), we are currently using Python's property to make data attributes accessible in a controlled way. Unfortunately, theseproperty
s don't mix well with inheritance. This article describes how to still make it work for thegetter
part, but since we would still have to repeat the same number of lines in the data files, I'm not sure it's worth the effort here. What we stand to gain is a separation of functionality and placeholder code, it seems to me. So when we want to make changes to how e.g.data
is returned from an optimization model, we would just need to change one place and all others would inherit these changes. However, code repetition would not be decreased and understanding the models might become more complicated, so I've put this on hold for now.For
TableRepository
, there is luckily a quite straightforward way: we can employ the same approach as in the DB layer and create anOptimizationBaseRepository
in the core layer that can be extended withCreator
,Retriever
, etc as needed. This seems to work well and every optimization item repo then just needs to clarify which_model_type
and_backend_repository
it is interested in.For better understanding, I wanted to type hint the
_backend_repository
in theOptimizationBaseRepository
. However, we didn't already have an appropriate object to do so. That's why I have created aBackendBaseRepository
inabstract.optimization.base
, which simply announces how the actualTableRepository
in the DB layer is going to look. I'm not sure if this is the correct location; I've usually worked with abstract models to type hint API/DB layer functionality, but I also don't know where else it would live.This is the point where I'm not sure I'm naming things correctly anymore. I started from
Table
, which already hasTable.data
, which is arguably the largest part of shared functionality, at least in the DB layer, and which is missing fromIndexSet
andScalar
. So these two items could not use theOptimizationBaseRepository
as it is now, which seems like a misnomer. Maybe the data functionality needs to be further separated (allowing us to DRY even more parts of this layer) or maybe we find another name?The same applies for
BackendBaseRepository
.Note
For the curious: there's an issue on CPython about
property
s and inheritance from 2012.