You need to implement a push() method for your new element if the pushed copy of the element uses the previous element in some way. For example, accumulated elements such as the SoProfileElement( C++ | Java | .NET ) need the previous element because they append values to the previous values. Their push() method copies the values from the previous element in the stack into the new element on the stack so that the current value can be appended to it. You also need to implement a push() method if your element requires some side effect when its value is set. For example, some matrix elements call glPushMatrix() inside their push() routine. You do not need to implement a push() method for most replaced elements (unless they have side effects), since their new value wipes out the previous value.
The push() method is called when you call set() on an element for the first time after the state is pushed (for example, underneath a separator). You may need to implement a corresponding pop() method whenever you implement a push() method for an element.
If your pop() method has side effects, those side effects need to be included in a cache for the separator that performs the pop; otherwise, the separator cannot restore the state properly. Include this line in an element's pop() method to tell all open caches they need to depend on this element when validating a cache:
capture(state);
For example, suppose the scene graph contains a draw-style node with a value of FILLED. A separator node to the right of this draw-style node contains a draw-style node with a value of LINES and a cube. Assume caching is turned on at the separator node. The separator's cache contains instructions for setting the draw-style to LINES and drawing the cube. When the state is restored, the draw-style element's pop() method causes the draw-style to be restored to its previous value (FILLED). If that previous value changes, this separator's cache is no longer valid.