-
Notifications
You must be signed in to change notification settings - Fork 707
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
Configuration of I/O of ParameterHandler #9888
Comments
Is the idea to use My way to address the question regarding a good design would be to look at the code and choose a design for which the implementation is most simple and easy to understand. In my experience this also leads to a user friendly interface. I'm not sure if the user interface is simpler when setting up a data structure instead of calling the function with an additional parameter. The fact that both standard and short versions are entities of Can you give a concrete example illustrating that the suggested design leads to simplifications? |
This would allow a code like
which is much better, in my opinion, w.r.t
where The code path is actually simpler:
etc. Why do you think it would be more complicated? |
Agree with @luca-heltai! |
What about such an Assert in
@luca-heltai Maybe I did not understand you correctly, but you say that |
It should be enough to check
|
So we can consider this a bug in the current implementation? My point is that you have to change the code, not that you can fix it. |
@luca-heltai Regarding complecity, how does the number of entities of |
Another example taken from
A better design in my opinion is using a bool
Maybe one can also write the above code example more elegantly with the new |
I suspect it is wrong, also
I think we should take care of not giving the user the possibility to make mistakes, such as choosing |
That's a good and elegant solution for sure, but - as already stated by @luca-heltai - it is poorly scalable as the number of inputs increases! |
Why not choosing a design where errors are excluded by design? |
What do you mean exactly by |
to be more precise, not every parameter will enter every function within the implementation |
So |
I only mean that the number of inputs would necessarily grow in case new options need to be added: one more input for every new option to set. |
Ok, I agree. Maybe I just don't know what you plan for the future. Regarding the current code version, I actually do not have the impression that interfaces are too fat. |
@luca-heltai: Regarding your example
which is much better, in my opinion, w.r.t
Why don't you need a class name or namespace in front of |
Thanks for the vivid discussion! Let's wait until the weekend to make a final decision. Personally I would favor the new enum-approach. @nfehn Regarding your comments:
|
I hope you don't feel accused because of the bug but I am convinced that we have to discuss these things concretely and not with It has also been referred to |
It can be something like: enum OutputStyle {
Short = 0x0001,
Alphabetical = 0x0002,
MarkMandatory = 0x0004,
Text = 0x0010,
LaTex = 0x0020,
Description = 0x0040,
XML = 0x0080,
JSON = 0x0100,
} Then you can check (omitting the namespace for brevity): if ((style & Text) && (style & Short)) // ShortText
...
if ((style & XML) && !(style & Alphabetical)) // Unsorted XML with documentation.
... and so on.
I don't know either what is coming in the future! But we better get ready, since in my opinion the effort of writing a more general and user-friendly interface using bitwise flags is the same than other approaches, so it is worth it! 😄 |
@elauksap
For me, this is a |
@luca-heltai regarding the example in the beginning: I agree regarding the idea, but there is more to it (I will skip
Is this really much simpler than
or using the new function introduces in #9862
? I agree that a sequence of Now imagine a user wants to explicitly have the option
(some logic in the program might change the value of these bools)? would you write the call to I have the concern that we will give up a lot of flexibility by the |
This is not performance critical code. It will be run once (maybe twice) per program. I don't think we should worry about the "code complexity" at all. I don't really care how ugly the code looks like internally. What I care about is the following observation: we have been struggling in the past in several places where we had booleans , and then every function call in the user code became
and everybody had to look up the documentation all the time to figure out what was wrong. Now think about the case in which you name your booleans, in order to document what is happening:
well, now you call the function with
but you get this wrong, and for some reason, you write:
I find myself doing this type of mistakes a lot. This means that the function is badly designed. I don't care that internally things may look more complicated with the enum design, but if you need to pass more than one boolean to a function, it is something that will cause bugs in user codes that are always difficult to find. No matter if it is "easier" internally, we should at all cost avoid this. Think of FEValues: would you want to have
or
The first option is not acceptable (IMHO). |
I agree with @nfehn that the extended enum is somewhat a struct with one enum ( Just like @luca-heltai, I don't like such long parameter lists (what is one reason for this issue). Let's quickly think through the pros and cons of a struct?
Are there any other issues, I did not think of? I have thought a bit how it might be possible to integrate such a struct in a way without breaking backwards compatibility:
Have I forgotten any aspect? The question would be also store this struct within the |
Sorry, there has been a misunderstanding, I am talking about complexity from an OO design perspective.
Unfortunately I do. Are we really already at the point that the discussion needs to be stalled like this? I agree with the points in which your preferred design makes certain things simpler at first sight, but I have the feeling you currently do not address the problems it will raise. Your If you think that are too many boolean parameters, you can introduce a struct with reasonable default values where the user only sets those parameters he is currently interested in, just as in your FEValues example. If some of the parameters are variable and are changed by the application program, your examples will look more difficult as well. The discussions of this issue can be split into two categories:
I currently have the feeling we mix up certain things. @luca-heltai You are voting for a common data structure, but you did not convince me that the enum design is the right way to go in terms of all the concerns raised above. |
I claim you can also not do this in general for the enum design (hence, is it really a con of the struct design?), see
|
I think
I don't think that writing in one line is an issue: how many lines do you need to define your booleans (if you want to use named booleans and document the code to yourself)? The current user interface was introduced in 9.2pre: in other words, now it is the right time to make a choice and make sure that whatever we have introduced after 9.1 is reverted (if we opt for one OuputStyle enum). After 9.2, this will be much more complicated. Again, since there has been a lot of work in this area lately, and I know from @elauksap that other changes will probably be needed, going through the route of >1 boolean as arguments is really not a realistic option.
You should stop taking comments on code design personally. There is no stall in the discussion. Allow me to disagree on the need of a struct: we really only need one enum. If you think it is not appropriate to mix
The users who have bools in their code are the users who have developed their code base only on the development branch (9.1 does not have
what is the flexibility you are referring to? The flexibility I have in mind is the following: anything that changes the outcome of
I don't think there we are breaking any backward compatibility. 9.1 does not have any boolean.
Why? The current version of the OutputStyle already does this (see here, for example OutpuStyle::Description which has the same logical role of "alphabetical", "short", etc. Our current enum already serves all our purposes, can be made backward compatible by splitting Maybe I'm not seeing what you refer to as "flexibility". Can you elaborate on this? |
I thought that this is not your honest conviction
For me, it seems you are following another intention by such statements, because I raised concerns that at some points the internal implementation might become more complicated. I gave concrete examples taken from the code and also identified a bug in the implementation. Instead you try to circumvent these discussions about the questions of interest and accuse me of taking things personally. Show me that I am wrong and that the internal implementation will become simpler. Don't worry, I won't take that personally. I'll accept and say you are right. I already mentioned that the aspect of code performance has been a misunderstanding, why do you continue in this direction
In a similar direction, I would be happy if you could explain what you wanted to tell me with this statement
The number of lines depends on how many booleans one has and how long the names of the booleans are, and of course on the formatting of the files. I guess this is not what you wanted to hear. Again, I have the feeling that you follow another intention with this statement, namely that the argument "writing in one line" introduced by @peterrum can be skipped because you don't like it.
I elaborated on this and even repeated it again with clear hints. I think it does not make sense to make the discussion longer and longer. I raised questions directly to @luca-heltai above. Once they are answered, I will elaborate on that. |
I don't know why, but this has become a bit too personal. It looks to me you are getting frustrated over this argument. That's not my intention, was not my intention, and I apologize if you get frustrated about this. Let's go back to code. I cannot find real questions in your comments, just a general sense of frustration which I did not want to provoke. Let me be clear about what I meant: Any code path internally can be translated to the version you advocated by two lines at the beginning:
I'm perfectly fine with having two such lines at the beginning of the implementation, so that nothing of what anybody wrote for the implementation needs to change. If this is the flexibility we are discussing about (again, it is internal, in the implementation of the library, and does not affect users), then there is no point in the whole discussion. The question I raised is only on the user interface, and so far I saw no (reasonable) arguments in favour of a collection of booleans beeing better than bitwise "or"-operations. Again, as long as there are at least two boolean as arguments, this is bad design, bug prone, and difficult to document in the code. This is the only sensible question to discuss about, and the only one that is difficult to change later on after the release. Please, leave alone the internal implementation. If you think a boolean is better for the internal implementation, one line of code at the beginning of the implementation is all we need. Maybe this was not clear with my "I don't care how ugly it is". Also, if you have codes in which a boolean is created by you, or in a parameter file, stating "output short style", then you can do the reverse, which also documents your code better:
This is flexible, and makes sure that By the way, it is VERY easy to make a Patterns::OutputStylePattern, that converts a string to one enum.
which, again, is much better to me than
so also from this point of view, I see no advantages in having booleans + OuputStyle. We have been using this type of programming style since 1997, and every time this was violated (by myself several times as well!), we regretted this. We have had many discussions like this in the last 10 years over a lot of enumeration classes of deal.II. This should also be taken into account when deciding for an interface. I'm sorry that the tone of the conversation became so harsh, and I apologize if it was my fault. |
I think you made your point clear that a bitwise enum = a collection of booleans, and I like that the discussion is beginning to become more open. Now by looking at Hence, there is more structure in the enum then one can identify by only looking at the declaration of the enum |
I think for a decision one needs to compare to the alternative
Let me explain the advantages such a design could have:
Disadvantages:
Suggestion to a solution for this disadvantage: write a free function that does the translation between @luca-heltai Could you please briefly complete the list of cons to make a decision? |
It isn't quite correct that the
or
It's of course a semantic bug to do this, but the language doesn't prevent you from doing it -- in the same way as you're not prevented from writing
in @luca-heltai 's style. In reality, one would have to write assertions in either case; in practice, we often haven't and then what happens is that you either get the first
or you end up in the
My personal preference would be to go with the single |
Yes, I agree. Maybe I should have written |
@bangerth Also for plain enums, implicit conversions are actually only possible from enum to int, not in the other direction?
I don't think so: I think you will have to write
similarly, you will have to write
Did you assume that the operator Apart from these semantic discussions, I originally hoped we could have discussed the approach from a design perspective. As I realized now, alea iacta est. |
Yes, this is true. The compiler is not able to implicitly cast
This is exactly what I personally dislike in your approach. Also, I think that keeping the two booleans separated from Moving rather to the objective design perspective: what happens if a user would like to print the same
which can be error prone and very obscure to read without having the documentation at hand, or, more verbosely,
which is, on the other hand, very unconvenient to write With the single
In both designs, the complexity of checking that the user has set an admissible combination of flags is hidden inside the class implementation and in my opinion it is not something we should be concerned about. The level of complexity here relies only on the level of defensiveness desired for the library programming style. The simplest approach, where one either falls into the first |
I am not sure about this. Let's make another example/comparison
@elauksap Can you write the same code in your favorite version? Please also use |
@nfehn you are right, perhaps it is not more error prone than writing But sorry I don't understand your question. By the way, if this was the case it would still be legal to write, e.g.:
|
"unconvenient" and "error prone" might be debatable. Could we first make the comparison please? What do you have to lose? Otherwise I get the impression you are picking those examples that underpin your hypothesis. Again, please use |
We can debate the meaning of "unconvenient", but not that 5 lines of code are more than 1 😄 Sorry again, I don't really get your question so I'm not able to answer. What is "the comparison" you are referring to? You asked
and I replied in my last comment. What other comparison would you like to see? |
This code is written in the
Can you write the same code in your favorite As a motivation, assume tests are implemented with the boolean interfaces calling other functions with these interfaces. Assume complex application codes that use other interfaces etc. |
@nfehn sorry, but why should we choose the design depending on whether some test or application prefers to use By the way, I already answered to your question in a previous reply, so I don't know why you keep asking it. |
For the sake of completeness, a one-liner would still be possible in the context you mentioned:
Does this make sense to you? |
Now, please add |
I don't want this discussion to become (again) a personal attack, but we just got to the point of discussing about how long one line of code would become when writing the full scope names, in a case that will most likely never happen (there would be no reason to keep independent boolean variables if we provided the single I think I had the chance to express all of my opinions, so I'm not going to indulge further provocations, unless you show a clear case where your solution gives and undisputable advantages with respect to the other one. |
We are currently discussing one argument. Let's do one step after the other. Let's please complete this argument and then we go on with the next. |
Sorry, you can't accuse me of trying to bring facts on the table. Here is a suggestion, please correct me
|
Templatize
At least, assuming that it is really relevant to provide compatibility with a pointless interface (personal opinion)... |
Type |
Yes, at least in a strongly defensive programming style. Or we can stick with the solution pointed out by @bangerth. Or we may decide that |
Not really, you asked me for the advantages of the |
First, this has nothing to do with the Second: yes, I agree that this can be an advantage for the internal implementation of the class, but it also results in multiple (debatable) disadvantages from the users' perspective (see above for a more complete discussion). It's a personal point of view, but I've always preferred an approach where developers take care of the implementation difficulties at their best, but giving users a more friendly interface. |
Let be briefly point to #13284 and #13290 (comment) given that @luca-heltai (receiving many "thumbs up") was strongly arguing with |
Recently there have been a couple of additions to the
ParameterHandler
class, in particular to its I/O functionalities.In the case of output, the additions are:
ShortXML
andShortJSON
sort_alphabetical
flagTo handle all the new cases and the old cases and to be backwards compatible, we could modify the
OutputStyle
the following way:Any options on such a way to configure the output style (motivated by update flags of
FEValues
)?In the case of input, the additions are:
skip_undefined
for XML and JSON filesassert_mandatory_entries_are_found
Wouldn't it be a good time to introduce a struct for these so that the list of defaulted parameters in function call doesn't become too long?
@elauksap @nfehn This might be also relevant for you.
The text was updated successfully, but these errors were encountered: