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.


Reply via email to