On Monday 30 November 2009 11:18:13 Russell Keith-Magee wrote: > > 1) Handling non-existent variables > > ================================== ... > > To do this properly, I think the best approach would be something > > like "almost three valued logic", which would work as follows: > > > > 1) variables that don't exist are represented by Null > > 2) all operators return either True or False, never Null > > 3) for 'not', 'and' and 'or', Null effectively acts like False > > (so "not Null" == True, "Null or True" == True etc) > > 4) for all comparison operators, if either argument is Null then > > the result is False e.g. "Null == Null" is False > > "Null > 1" is False, "Null <= 1" is False, except > > "!=", which should return true if either value is Null. > > > > Any comments on this approach? I've started to implement this, > > and it works OK so far, just needs a bit more work. > > I was with you right up until the equality comparisons (Null == > Null -> False etc). As noted by Alex, it conflicts with the answer > given by {% ifequal %}; it also differs with Python's behavior.
Yeah, I hadn't thought of that. I don't think it's a case of differing with Python's behaviour, as we are making a deliberate choice to substitute a missing variable with None (or Null or whatever). You could argue that Python throws a NameError in this case. I was trying to think about what is intuitive. e.g. what should happen here if foo has not been supplied: {% if foo < 1 %} yes {% endif %} I think it is fairly counter-intuitive for a template author that you get 'yes' here. However, on further reflection, the "almost 3 valued logic" can be equally counter-intuitive, say with the following case: {% if foo < 1 %} yes {% else %} no {% endif %} It would render 'no' if foo was missing, but it might be quite surprising that if you decided to re-arrange the template by inverting the logical condition: {% if foo >= 1 %} no {% else %} yes {% endif %} then you get different behaviour. (i.e. 'yes' if foo was missing). So, I'm *now* suggesting that we convert everything missing to None. In fact, I've found that doing anything apart from this would be hard. (Alex, you were right about what Malcolm had done with FilterExpression, which resolves the problem with TEMPLATE_STRING_IF_INVALID, but this gives me None instead of '', and not information about whether the variable actually exists, which is a slightly different question. I didn't find this out earlier because most of the tests are against the 'IfParser' which is a subclass of 'TemplateIfParser', and works slightly differently, and because I wasn't thinking properly). Behaviour of 'not' - revisited ============================== I think this leaves just the behaviour of 'not'. It is a bit more complicated than Alex suggested — the tests include "if not" and "if not not", and with the current behaviour you can do things like "if foo and not not" etc. In fact, you can do it (to some extent) with *any* of the keywords e.g. "if and", "if x and or". But not always e.g. "if not or and x" - that, illogically, is a syntax error. I suspect that allowing everything that was possible before will be extremely difficult, because the current behaviour is very badly defined for these edge cases — it works just fine if you do sensible things like not using variables called 'not', 'and' or 'or', but working out the rules for the exceptional cases will be very hard. I propose a backwards incompatibility here, it looks like this: The 'if' tag no longer accepts 'and', 'or' and 'not' as valid variable names. Previously that was allowed in some cases even though they were normally treated as keywords. Now, the keyword status is always enforced, and code like {% if not %} or {% if and %} will throw a TemplateSyntaxError. This would now be the only backwards incompatibility (discounting the possibility that people were relying on TemplateSyntaxError for things that are now legal). Patch ===== It can be tracked in my 'lp-smartif' branch here: http://bitbucket.org/spookylukey/django-trunk-lukeplant/ Currently various tests about 'not' are failing, and docs are not written. Chris: in the course of my attempted 'Null' behaviour changes, I changed your implementation slightly — I added explicit classes for Less, LessOrEqual, NotEqual and Not, pulling out the 'negate' behaviour from the individual classes (it made implementing the Null logic simpler). Other than that, very little of the parsing has changed. Given that the 'Null' stuff has now been removed, we could move back to your way to reduce the code a bit, but I'm not sure it is worth it. Review would be welcome, especially as I'm ill at the moment. I'm only coding because the boredom of doing nothing is killing me... Luke -- "Humiliation: The harder you try, the dumber you look." (despair.com) Luke Plant || http://lukeplant.me.uk/ -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-develop...@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.