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

Nesting exercises leaves \ExerciseID with a wrong value #57

Closed
N-Coder opened this issue Feb 25, 2020 · 6 comments
Closed

Nesting exercises leaves \ExerciseID with a wrong value #57

N-Coder opened this issue Feb 25, 2020 · 6 comments
Labels
duplicate this has been reported earlier suggestion suggestions and feature requests

Comments

@N-Coder
Copy link
Contributor

N-Coder commented Feb 25, 2020

See also my comments here, sorry if I made them in the wrong place.

To summarize, the issue is that the global variables \ExerciseID and \ExerciseType (and also the internal \g_xsim_exercise_id_tl) are only set whenever entering (any custom type of) the exercise environment. This works when having a flat structure of exercises. But when using a structure similar to Example 30: Exercises and sub-exercises (and which is also commonly used for exams) this behaviour breaks because right before the end of the parent exercise, but already after the end of any child exercises, the current exercise variable will still point to the last child exercise (see the image here, where the last line should read "/ID 1", but actually says "/ID 3"). This is a problem for templates that use this variable after the exercise content, but may also prevent solutions (esp. solutions for the parent exercise) from using the correct exercise ID.

My initial approach to fix this was reverting the changes to the global variables made in \xsim_start_exercise using a post-hook (or alternatively \xsim_stop_exercise). This fixed the wrong values in the end part of templates and also yielded a nice way of accessing the hierarchical exercise structure through the container property. Unfortunately, this made the solution-ID problem worse.

I guess the underlying issue is that there are different views on what the "current exercise" variable should actually point to:

  • currently, it just points to the value that was last assigned in \xsim_start_exercise and is not changed when an exercise ends. This means that the previously used exercise is still available as "current" even after it ended, which allows for the correct linking with the respective solution (and also allows all the property accessor commands to function outside of - or more precisely after - an exercise environment within the remaining document). Unfortunately, this also leads to this exact bug when nesting exercises.
  • to allow nesting, we want to know the innermost still active (i.e. not ended) exercise that we are actually contained in. So the semantics should be: set to a new value in \xsim_start_exercise and revert to the parent value in \xsim_stop_exercise, which is empty for root-level exercises. Outside of any exercise this value must be empty, as otherwise some form of nesting would be implied. This is the behaviour my code implements.
  • to provide the correct ID in solutions (which should afaik always appear right after their respective exercise), we want to know the solution that most recently ended. For non-nested use-cases this is the same as the one that most recently started, but with nesting this order might be different.

So maybe this one variable should be split into multiple one up to cater the different needs:

  • the \ExerciseID variable for end-users with mostly the same semantics as now, but a fix for using it after nested child exercises
  • a "parent" or "container" variable for tracking the nesting of exercises
  • a "sibling" or "previous" variable for tracking the exercise a solution belongs to

@cgnieder what do you think about this proposal? If it sounds good to you, I can try to implement this and open a PR. Alternatively, this functionality could be implemented in an opt-in fashion, but I'm unsure how to realize this. Maybe this could be done by adding hooks that don't interfere with other hooks set by the user (if that is possible) and using XSIM modules?

@cgnieder
Copy link
Owner

Yes, nesting exercises is not supported right now. Actually this was a deliberate decision when I started drafting the first versions of xsim.

What I do plan for the (hopefully not so far) future is to provide a native mechanism for “sub-exercises”. Such a mechanism would make nesting superfluous IMHO.

@cgnieder cgnieder added the suggestion suggestions and feature requests label Feb 25, 2020
@N-Coder
Copy link
Contributor Author

N-Coder commented Feb 27, 2020

Actually I like the idea of nesting exercises quite much because it gives you full flexibility when realizing whatever concept of subexercise you have. You can add text above and below the enumeration and even stop it in the middle, add some general remarks, and have it continue afterwards - or even use a completely different way of arranging and layouting the subexercises (e.g. your tasks environment). Additionally, you can use any depth of nesting you need - i.e. add subsubexercises to your subexercises.

I put some more thoughts into my approach at providing/fixing this and realized that it is actually easier than I first thought and there is no problem with the internal architecture of XSIM preventing this. By reverting the global exercise ID to the value from the pre-hook in the end-hook, not the post-hook, I make sure that any footer template and also following code get the right ID, and not some other value set within the body of the exercise. You can check out an example using the current version on overleaf. All the IDs in the example are correct.

I also put my code into two XSIM modules - one for the fix for nested exercise IDs and for summing up nested points - which can easily be loaded as opt-in. From my point of view those would be ready for general availability. Would you want to include them in XSIM?

@cgnieder
Copy link
Owner

cgnieder commented Mar 8, 2020

After thinking about this for a while I think you are right that \ExerciseID and \ExerciseType can safely be set locally (as long as \g_xsim_exercise_id_tl stays global). I have implemented this in commit 0f90bd6

\documentclass{article}
\usepackage[enable-debug]{expl3}
\usepackage[no-files]{xsim}

\DeclareExerciseType{subquestion}{
  exercise-env = question ,
  solution-env = answer ,
  exercise-name = Question ,
  solution-name = Answer ,
  exercise-template = item ,
  solution-template = item
}

\DeclareExerciseEnvironmentTemplate{item}{\item}{}

\begin{document}

\begin{exercise}
  \ExerciseType:\ExerciseID
  \begin{enumerate}
    \begin{question}[ID=sub-a]
      \ExerciseType:\ExerciseID
    \end{question}
    \begin{answer}
      \ExerciseType:\ExerciseID
    \end{answer}
    \begin{question}[ID=sub-b]
      \ExerciseType:\ExerciseID
    \end{question}
    \begin{answer}
      \ExerciseType:\ExerciseID
    \end{answer}
    \begin{question}[ID=sub-c]
      \ExerciseType:\ExerciseID
    \end{question}
    \begin{answer}
      \ExerciseType:\ExerciseID
    \end{answer}
  \end{enumerate}
  \ExerciseType:\ExerciseID
\end{exercise}

\begin{solution}[print]
  \ExerciseType:\ExerciseID
  \begin{enumerate}
    \printsolution{subquestion}{sub-a}
    \printsolution{subquestion}{sub-b}
    \printsolution{subquestion}{sub-c}
  \end{enumerate}
  \ExerciseType:\ExerciseID
\end{solution}

\end{document}

image

@cgnieder
Copy link
Owner

Can this be closed?

@N-Coder
Copy link
Contributor Author

N-Coder commented Mar 24, 2020

Thanks, that should fix the bug I tried to patch with my code! Unfortunately, I couldn't try it out myself, yet. Do you have any recommendations on how to set up an environment with the current version from git?

In addition to fixing the bug, the two modules I wrote also store the nesting hierarchy (i.e. the parent of each exercise) into an exercise property and provide help with summing up the points of all nested child exercises. Would you be interested in including this in the xsim library as an opt-in module?

@cgnieder
Copy link
Owner

I am very much interested in your thoughts, especially from a users points of view.
I opened an issue for this and will close this thread as a duplicate of it: issue #67

@cgnieder cgnieder added the duplicate this has been reported earlier label Mar 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate this has been reported earlier suggestion suggestions and feature requests
Projects
None yet
Development

No branches or pull requests

2 participants