Discussion:
[Freemarker-devel] 2.4: Prohibit null as macro/function parameter like we do with "undefined"
Daniel Dekany
2007-06-06 20:21:54 UTC
Permalink
Starting from FreeMarker 2.4 FTL will have both null and undefined.
(Before 2.4 we only had undefined in FTL, and null-s coming from the
"Java world" was treated like undefined). And while with 2.4, if some
really wants to, one can deal with Java null-s properly, we should
also keep the old approach. Like, exp!'N/A' should evaluate to 'N/A'
both if exp is undefined and if it is null. And this is how it works
now, except with macro and function calls. I think that FTL macro-s
and functions should disallow passing in null value as parameter,
unless in the declaration of the macro/function a default value was
given, or it was explicitly specified that the macro/function
"understands" null-s as the parameter value (something like
<#macro m p{bypass_null}>). This not only would be more consistent with
the "null and undefined is the same" approach, but I think it would be
practical as well. It's a crucial question, so we must not make a mistake in this.

To reemphasize my most shocking(?) point, this should fail be saying
that the x parameter was null:

[#macro foo x]
Mooo!
[/#macro]

[@foo null /]

BTW, it should be settled before the Preview 1, because it has quite a
backward compatibility impact. My recommendation happens to be the
more backward compatible, but it wasn't my goal with it.
--
Best regards,
Daniel Dekany
Leandro Rodrigo Saad Cruz
2007-06-07 00:51:20 UTC
Permalink
IMHO, freemarker should support nulls "completely". By completely I mean.

- allow null from method return: <#assign maybeNull = obj.returnsNull() />
- assigning null to a var: <#assign maybeNull = obj.returnsNull() /> or
<#assign maybeNull = null />
- pass null as a macro param.
--
Leandro Rodrigo Saad Cruz
software developer - certified scrum master
:: scrum.com.br
:: db.apache.org/ojb
:: guara-framework.sf.net
:: xingu.sf.net
Post by Daniel Dekany
Starting from FreeMarker 2.4 FTL will have both null and undefined.
(Before 2.4 we only had undefined in FTL, and null-s coming from the
"Java world" was treated like undefined). And while with 2.4, if some
really wants to, one can deal with Java null-s properly, we should
also keep the old approach. Like, exp!'N/A' should evaluate to 'N/A'
both if exp is undefined and if it is null. And this is how it works
now, except with macro and function calls. I think that FTL macro-s
and functions should disallow passing in null value as parameter,
unless in the declaration of the macro/function a default value was
given, or it was explicitly specified that the macro/function
"understands" null-s as the parameter value (something like
<#macro m p{bypass_null}>). This not only would be more consistent with
the "null and undefined is the same" approach, but I think it would be
practical as well. It's a crucial question, so we must not make a mistake in this.
To reemphasize my most shocking(?) point, this should fail be saying
[#macro foo x]
Mooo!
[/#macro]
BTW, it should be settled before the Preview 1, because it has quite a
backward compatibility impact. My recommendation happens to be the
more backward compatible, but it wasn't my goal with it.
--
Best regards,
Daniel Dekany
Daniel Dekany
2007-06-07 02:12:33 UTC
Permalink
Post by Leandro Rodrigo Saad Cruz
IMHO, freemarker should support nulls "completely". By completely I mean.
- allow null from method return: <#assign maybeNull = obj.returnsNull() />
- assigning null to a var: <#assign maybeNull = obj.returnsNull()
/> or <#assign maybeNull  = null />
- pass null as a macro param.
It supports all of these (in 2.4). It was about how FTL
macros/functions behave when they receive a null as they parameter and
you didn't explicitly specified that it can handle null. (BTW this
thing that languages by default accept null-s as
method/function/procedure parameters, and that you have to be explicit
if you do *not* want to allow it is IMO just a bad inheritance of the
old performance-focused languages like C. I wonder if any mainstream
language will ever dare to deviate from it. I'm afraid not.)
--
Best regards,
Daniel Dekany
Attila Szegedi
2007-06-07 08:17:56 UTC
Permalink
Post by Daniel Dekany
To reemphasize my most shocking(?) point, this should fail be saying
[#macro foo x]
Mooo!
[/#macro]
This doesn't feel right to me. In my mind, macros are refactoring devices
-- if I have duplicate code, I extract it into a macro, and invoke the
macro from multiple locations. So, if I had

---
${blah!N/A} ${foo!N/A}
---

in my template, and replaced it with

---
[#macro na x]
${x!N/A}
[/#macro]

[@na blah] [@na foo]
---

I would expect it to behave the same even if blah or foo are null. This is
actually something that's been bothering me with undefined values in
pre-2.4 FM as well.

Attila.
--
home: http://www.szegedi.org
weblog: http://constc.blogspot.com
Daniel Dekany
2007-06-07 10:47:33 UTC
Permalink
Post by Attila Szegedi
Post by Daniel Dekany
To reemphasize my most shocking(?) point, this should fail be saying
[#macro foo x]
Mooo!
[/#macro]
This doesn't feel right to me. In my mind, macros are refactoring devices
-- if I have duplicate code, I extract it into a macro, and invoke the
macro from multiple locations. So, if I had
---
${blah!N/A} ${foo!N/A}
---
in my template, and replaced it with
---
[#macro na x]
${x!N/A}
[/#macro]
---
I would expect it to behave the same even if blah or foo are null. This is
actually something that's been bothering me with undefined values in
pre-2.4 FM as well.
I see what you mean, but then now we also should allow:

[#macro na x]
${x!N/A}
[/#macro]

[@na totallyWrongVariableName]

But we don't want to allow that, right? That said, macro calls are not
just like delayed copy-pasting -- that's approach is used by Velocity.
Instead they are like functions/methods/procedures of usual languages.
--
Best regards,
Daniel Dekany
Jonathan Revusky
2007-06-07 10:56:32 UTC
Permalink
AFAICS, what it does now is about right. If you pass in something that
is deliberately null, that is okay, but if it is a mispelled variable
name, you get an exception.

Attilla, as for this bothering you in pre-2.4, presumably, using 2.4,
the nul variables you'd be passing around would be genuine nulls, i.e.
TemplateModel.JAVA_NULL, and that would be okay. We didn't have the
distinction before.

JR
Post by Attila Szegedi
Post by Attila Szegedi
Post by Daniel Dekany
To reemphasize my most shocking(?) point, this should fail be saying
[#macro foo x]
Mooo!
[/#macro]
This doesn't feel right to me. In my mind, macros are refactoring devices
-- if I have duplicate code, I extract it into a macro, and invoke the
macro from multiple locations. So, if I had
---
${blah!N/A} ${foo!N/A}
---
in my template, and replaced it with
---
[#macro na x]
${x!N/A}
[/#macro]
---
I would expect it to behave the same even if blah or foo are null. This is
actually something that's been bothering me with undefined values in
pre-2.4 FM as well.
[#macro na x]
${x!N/A}
[/#macro]
But we don't want to allow that, right? That said, macro calls are not
just like delayed copy-pasting -- that's approach is used by Velocity.
Instead they are like functions/methods/procedures of usual languages.
--
Best regards,
Daniel Dekany
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
FreeMarker-devel mailing list
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany
2007-06-07 11:16:43 UTC
Permalink
Post by Jonathan Revusky
AFAICS, what it does now is about right. If you pass in something that
is deliberately null, that is okay, but if it is a mispelled variable
name, you get an exception.
That was clear; you doesn't seem to really address what I said. OK,
for starters, consider this: is it a good idea that the default value
of macro parameters is not used if the value received for the
parameter is null (not undefined)? I mean, surely you can reason for
it on theoretical grounds (i.e. that the parameter was specified in
the caller site), but does it make sense practically? Like if you have
foo.bar used as macro parameter that has a default value, and foo.bar
is an existing bean property whose value is null (which is the way in
Java to indicate "missing"), then didn't you meant to use the default
value of the parameter? And if in the same situation foo is a Map,
that doesn't contain the key "bar"? (Note that the template author
doesn't see if which is the case -- bean or map.)
--
Best regards,
Daniel Dekany
Jonathan Revusky
2007-06-07 14:01:45 UTC
Permalink
Post by Daniel Dekany
Post by Jonathan Revusky
AFAICS, what it does now is about right. If you pass in something that
is deliberately null, that is okay, but if it is a mispelled variable
name, you get an exception.
That was clear; you doesn't seem to really address what I said. OK,
for starters, consider this: is it a good idea that the default value
of macro parameters is not used if the value received for the
parameter is null (not undefined)?
I'm not 100% sure. I have been thinking about it.

Well, I grant, you're probably right about the above point -- as usual.

However, I see that as a separate issue from what happens if you pass in
null or undefined variable when there is no default value defined for
that argument.

When there is no default value, it seems to me to be very logical to say
that the null deliberately defined as null (i.e. coming from a java API
or just a [#set foo = null] should be passed in and the undefined value,
which is likely the result of a misspelled variable name, should cause
an exception.

As for what happens when you have a default value, it seems that,
probably, you should go to the default value if it's a true deliberate
null, but still blow up when it's truly undefined. Otherwise, what are
you saying? That we have this default value here just in case you
misspelt a variable, so that we can keep going? That obviously isn't the
purpose of a default value, is it?
Post by Daniel Dekany
I mean, surely you can reason for
it on theoretical grounds (i.e. that the parameter was specified in
the caller site), but does it make sense practically? Like if you have
foo.bar used as macro parameter that has a default value, and foo.bar
is an existing bean property whose value is null (which is the way in
Java to indicate "missing"), then didn't you meant to use the default
value of the parameter? And if in the same situation foo is a Map,
that doesn't contain the key "bar"?
Well, I think the approach is that, if you want the subvariable to be a
genuine null, you have to explicitly put it in the map, and you can use
map.put("foo", null) on the java side to do that. (The default object
wrapper implementations will massage that to a TemplateModel.JAVA_NULL
in the wrapped FTL hash object...)

(Note that the template author
Post by Daniel Dekany
doesn't see if which is the case -- bean or map.)
That's true enough, but it is up to the java programmer to define the
data model. And to communicate what is in the data model to the person
working on the template layer. The problem was that, before this release
cycle, a java programmer had basically no way to distinguish between a
deliberate null and something being null just because it was missing
(i.e. probably a misspelt variable) but now the distinction is clear.

JR
Daniel Dekany
2007-06-07 14:48:17 UTC
Permalink
Post by Jonathan Revusky
Post by Daniel Dekany
Post by Jonathan Revusky
AFAICS, what it does now is about right. If you pass in something that
is deliberately null, that is okay, but if it is a mispelled variable
name, you get an exception.
That was clear; you doesn't seem to really address what I said. OK,
for starters, consider this: is it a good idea that the default value
of macro parameters is not used if the value received for the
parameter is null (not undefined)?
I'm not 100% sure. I have been thinking about it.
Well, I grant, you're probably right about the above point -- as usual.
However, I see that as a separate issue from what happens if you pass in
null or undefined variable when there is no default value defined for
that argument.
When there is no default value, it seems to me to be very logical to say
that the null deliberately defined as null (i.e. coming from a java API
or just a [#set foo = null] should be passed in
The only problem is that usually null-s are not coming from such
sources, I mean, from source where you have explicitly specified null
*in the template*. They are coming from bean properties and return
values of Java methods.
Post by Jonathan Revusky
and the undefined value, which is likely the result of a misspelled
variable name, should cause an exception.
As for what happens when you have a default value, it seems that,
probably, you should go to the default value if it's a true deliberate
null, but still blow up when it's truly undefined. Otherwise, what are
you saying? That we have this default value here just in case you
misspelt a variable, so that we can keep going? That obviously isn't the
purpose of a default value, is it?
The treatment of the parameter expressions in the macro call and how
the macro reacts to the actual parameter values are separate issues.
For example *as far as the macro call statement is concerned*, this
should not cause error:

[#set x = null]
[@foo title=x /]

BUT the foo macro may will say that, "No thank you, I don't want a
null here. I wanted a title, and you have provided nothing. Because
null is just nothing as far as I'm concerned.". (And with the same
logic a default parameter value step in action of the parameter value
is null.)

Really, poor "foo" macro why should tolerate that null when it was not
designed to handle it? I think most macros are not designed to. Those
which are could explicitly declared as "I can handle a null as the
value this parameter". Something like {bypass_null} as I have shown.
(It's "bypass" and not "allow" because the null will avoid the default
value of the parameter, if there is one.)
Post by Jonathan Revusky
Post by Daniel Dekany
I mean, surely you can reason for
it on theoretical grounds (i.e. that the parameter was specified in
the caller site), but does it make sense practically? Like if you have
foo.bar used as macro parameter that has a default value, and foo.bar
is an existing bean property whose value is null (which is the way in
Java to indicate "missing"), then didn't you meant to use the default
value of the parameter? And if in the same situation foo is a Map,
that doesn't contain the key "bar"?
Well, I think the approach is that, if you want the subvariable to
be a genuine null, you have to explicitly put it in the map, and you
can use map.put("foo", null) on the java side to do that.
But almost nobody will, as we know. It's just not the way Map-s are
used in any language, and of course an MVC template language is not in
the position to dictate this.
Post by Jonathan Revusky
(The default object wrapper implementations will massage that to a
TemplateModel.JAVA_NULL in the wrapped FTL hash object...)
(Note that the template author
Post by Daniel Dekany
doesn't see if which is the case -- bean or map.)
That's true enough, but it is up to the java programmer to define the
data model.
And mostly up to us, as far as it comes to wrapping. Things just
should work senseful out of the box. The default wrapper is the prime
example of how things should work. If what is the best practice.
Post by Jonathan Revusky
And to communicate what is in the data model to the person
working on the template layer. The problem was that, before this release
cycle, a java programmer had basically no way to distinguish between a
deliberate null and something being null just because it was missing
(i.e. probably a misspelt variable) but now the distinction is clear.
So, concretely what would you do if you are "the java programmer" to
save the template authors from confusion?
Post by Jonathan Revusky
JR
--
Best regards,
Daniel Dekany
Jonathan Revusky
2007-06-07 15:24:59 UTC
Permalink
Post by Daniel Dekany
Post by Jonathan Revusky
Post by Daniel Dekany
Post by Jonathan Revusky
AFAICS, what it does now is about right. If you pass in something that
is deliberately null, that is okay, but if it is a mispelled variable
name, you get an exception.
That was clear; you doesn't seem to really address what I said. OK,
for starters, consider this: is it a good idea that the default value
of macro parameters is not used if the value received for the
parameter is null (not undefined)?
I'm not 100% sure. I have been thinking about it.
Well, I grant, you're probably right about the above point -- as usual.
However, I see that as a separate issue from what happens if you pass in
null or undefined variable when there is no default value defined for
that argument.
When there is no default value, it seems to me to be very logical to say
that the null deliberately defined as null (i.e. coming from a java API
or just a [#set foo = null] should be passed in
The only problem is that usually null-s are not coming from such
sources, I mean, from source where you have explicitly specified null
*in the template*. They are coming from bean properties and return
values of Java methods.
If they come from the return value of a java method or a bean property
(which is usually just getFoo() return value) then it is a java null,
just as if it came from [#set foo = null]

If it comes from a hash where the key/value pair was not put in
explicitly, then it is a missing value.
Post by Daniel Dekany
Post by Jonathan Revusky
and the undefined value, which is likely the result of a misspelled
variable name, should cause an exception.
As for what happens when you have a default value, it seems that,
probably, you should go to the default value if it's a true deliberate
null, but still blow up when it's truly undefined. Otherwise, what are
you saying? That we have this default value here just in case you
misspelt a variable, so that we can keep going? That obviously isn't the
purpose of a default value, is it?
The treatment of the parameter expressions in the macro call and how
the macro reacts to the actual parameter values are separate issues.
For example *as far as the macro call statement is concerned*, this
[#set x = null]
BUT the foo macro may will say that, "No thank you, I don't want a
null here. I wanted a title, and you have provided nothing. Because
null is just nothing as far as I'm concerned.".
Yes, but that error comes later, when the macro tries to dereference x
and expects a string, but gets a null. But no error occurs at the
point where the macro is invoked. Well, it does occur when the macro
is invoked if x is just undefined, but in the example above, x is not
undefined, it is defined, but null, the distinction we didn't have
before.

(And with the same
Post by Daniel Dekany
logic a default parameter value step in action of the parameter value
is null.)
Okay, I am willing to agree with you on that point, assuming it is a
true java null, and not simply an undefined variable. If it's just an
undefined variable, AFAICS, the code might as well blow up at the
first opportunity.
Post by Daniel Dekany
Really, poor "foo" macro why should tolerate that null when it was not
designed to handle it? I think most macros are not designed to. Those
which are could explicitly declared as "I can handle a null as the
value this parameter". Something like {bypass_null} as I have shown.
(It's "bypass" and not "allow" because the null will avoid the default
value of the parameter, if there is one.)
I don't see enough value added in introduing some extra bypass_null
keyword or something. We should just decide that JAVA_NULL gets turned
into the default parameter if a default parameter is present and
document that. And, as far as I'm concerned, we can just maintain a
policy of zero tolerance towards undefined variables.
Post by Daniel Dekany
Post by Jonathan Revusky
Post by Daniel Dekany
I mean, surely you can reason for
it on theoretical grounds (i.e. that the parameter was specified in
the caller site), but does it make sense practically? Like if you have
foo.bar used as macro parameter that has a default value, and foo.bar
is an existing bean property whose value is null (which is the way in
Java to indicate "missing"), then didn't you meant to use the default
value of the parameter? And if in the same situation foo is a Map,
that doesn't contain the key "bar"?
Well, I think the approach is that, if you want the subvariable to
be a genuine null, you have to explicitly put it in the map, and you
can use map.put("foo", null) on the java side to do that.
But almost nobody will, as we know. It's just not the way Map-s are
used in any language, and of course an MVC template language is not in
the position to dictate this.
Well, then we're just back to the same intolerant pre-2.4 behavior,
that we throw an exception because the expression is undefined. If you
want to be passing around nulls, you have to be explicit about your
intent. I don't see how we can do any better than this really.
Post by Daniel Dekany
Post by Jonathan Revusky
(The default object wrapper implementations will massage that to a
TemplateModel.JAVA_NULL in the wrapped FTL hash object...)
(Note that the template author
Post by Daniel Dekany
doesn't see if which is the case -- bean or map.)
That's true enough, but it is up to the java programmer to define the
data model.
And mostly up to us, as far as it comes to wrapping. Things just
should work senseful out of the box. The default wrapper is the prime
example of how things should work. If what is the best practice.
The default wrapper will wrap a java Map such that if there is a
key/null pair, the null gets massaged into the FTL JAVA_NULL singleton
and you can pass that around and it will get turned back into a
regular null if you pass it back into a java API method. If the
specific variable or subvariable is referenced but is not in the data
model, we get an exception.
Post by Daniel Dekany
Post by Jonathan Revusky
And to communicate what is in the data model to the person
working on the template layer. The problem was that, before this release
cycle, a java programmer had basically no way to distinguish between a
deliberate null and something being null just because it was missing
(i.e. probably a misspelt variable) but now the distinction is clear.
So, concretely what would you do if you are "the java programmer" to
save the template authors from confusion?
Well, personally, as the first-best solution, I would try to have a
data model which does not have any java nulls in it, like using the
empty string or empty sequence or hash and so on. When that's not
possible, because the java API you're exposing potentially has null
return values, I would make sure to document that the values are
potentially null, under certain circumstances. In those cases, the
nulls will be the FTL JAVA_NULL. But in that case, any other missing
value is just undefined and still blows up at the earliest
opportunity.

JR
Post by Daniel Dekany
Post by Jonathan Revusky
JR
--
Best regards,
Daniel Dekany
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
FreeMarker-devel mailing list
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany
2007-06-07 16:19:01 UTC
Permalink
Post by Jonathan Revusky
Post by Daniel Dekany
Post by Jonathan Revusky
Post by Daniel Dekany
Post by Jonathan Revusky
AFAICS, what it does now is about right. If you pass in something that
is deliberately null, that is okay, but if it is a mispelled variable
name, you get an exception.
That was clear; you doesn't seem to really address what I said. OK,
for starters, consider this: is it a good idea that the default value
of macro parameters is not used if the value received for the
parameter is null (not undefined)?
I'm not 100% sure. I have been thinking about it.
Well, I grant, you're probably right about the above point -- as usual.
However, I see that as a separate issue from what happens if you pass in
null or undefined variable when there is no default value defined for
that argument.
When there is no default value, it seems to me to be very logical to say
that the null deliberately defined as null (i.e. coming from a java API
or just a [#set foo = null] should be passed in
The only problem is that usually null-s are not coming from such
sources, I mean, from source where you have explicitly specified null
*in the template*. They are coming from bean properties and return
values of Java methods.
If they come from the return value of a java method or a bean property
(which is usually just getFoo() return value) then it is a java null,
just as if it came from [#set foo = null]
Er... so what's then? It seems to be an irrelevant fact for me. What I
tried to point out is that if the template author enters "null" *into
the template*, then obviously he knows that he deals with a Java null,
and certainly he really wants to play with Java null-s here. But when
he just innocently accesses the data-model, it's not necessarily clear
for him at all.
Post by Jonathan Revusky
If it comes from a hash where the key/value pair was not put in
explicitly, then it is a missing value.
Post by Daniel Dekany
Post by Jonathan Revusky
and the undefined value, which is likely the result of a misspelled
variable name, should cause an exception.
As for what happens when you have a default value, it seems that,
probably, you should go to the default value if it's a true deliberate
null, but still blow up when it's truly undefined. Otherwise, what are
you saying? That we have this default value here just in case you
misspelt a variable, so that we can keep going? That obviously isn't the
purpose of a default value, is it?
The treatment of the parameter expressions in the macro call and how
the macro reacts to the actual parameter values are separate issues.
For example *as far as the macro call statement is concerned*, this
[#set x = null]
BUT the foo macro may will say that, "No thank you, I don't want a
null here. I wanted a title, and you have provided nothing. Because
null is just nothing as far as I'm concerned.".
Yes, but that error comes later, when the macro tries to dereference x
and expects a string, but gets a null. But no error occurs at the
point where the macro is invoked. Well, it does occur when the macro
is invoked if x is just undefined, but in the example above, x is not
undefined, it is defined, but null, the distinction we didn't have
before.
But if the macro can't handle that null parameter anyway, then what is
the point of allowing it to blow later? Anyway there is no grantee
that it will blow at all. Like maybe it passes the null to another
macro that use a default value for its parameter, so the problem
remains hidden. (So note that it's not entirely backward compatible
with 2.3.x templates: it may won't blow as I said, also it can upset
things that utilize #attempt/#recover. Admittedly these will not be
frequent... But also, in wrong templates many error message will be
less helpful with 2.4.) Now sure, we can't tell if the author of the
macro have considered the case of null, but in almost all cases he
will not. So for most cases the natural and conventional thing, or at
least the better thing would be if a null parameters blow early. And
we have this opportunity to do it this way in FTL, because it would be
backward compatible. (<OT>As I said, I would prefer if Java Language
works this way as well. Did I say that the parameter can be null? Then
why does it let them be that? Nobody else is sick of writing those
explicit null checks everywhere, and then also manually documenting
for each parameter if it can be null or not? This all could be
auto-generated, and also the number of hard-to-track-down NPE-s --
that are often caused by programmers forget or not willing to do null
checks -- would decrease.</OT>) And in the remaining cases -- which
will certainly be a minority -- the user can be explicit about it,
like marking the parameter as null bypasser or something. Well, that
was what I wanted to say about it. You guys better sleep on it before
making the final decision.
Post by Jonathan Revusky
(And with the same
Post by Daniel Dekany
logic a default parameter value step in action of the parameter value
is null.)
Okay, I am willing to agree with you on that point, assuming it is a
true java null, and not simply an undefined variable.
Yes, that's what I meant. (Theoretically this all happens in the
macro, not in the macro call statement, with other words, after the
parameter expression were already evaluated. So of course if there
were an undefined variable, it blows before the macro has chance to
apply defaults and like.)

[snip]
--
Best regards,
Daniel Dekany
Jonathan Revusky
2007-06-08 19:17:50 UTC
Permalink
Post by Daniel Dekany
Post by Jonathan Revusky
Post by Daniel Dekany
Post by Jonathan Revusky
Post by Daniel Dekany
Post by Jonathan Revusky
AFAICS, what it does now is about right. If you pass in something that
is deliberately null, that is okay, but if it is a mispelled variable
name, you get an exception.
That was clear; you doesn't seem to really address what I said. OK,
for starters, consider this: is it a good idea that the default value
of macro parameters is not used if the value received for the
parameter is null (not undefined)?
I'm not 100% sure. I have been thinking about it.
Well, I grant, you're probably right about the above point -- as usual.
However, I see that as a separate issue from what happens if you pass in
null or undefined variable when there is no default value defined for
that argument.
When there is no default value, it seems to me to be very logical to say
that the null deliberately defined as null (i.e. coming from a java API
or just a [#set foo = null] should be passed in
The only problem is that usually null-s are not coming from such
sources, I mean, from source where you have explicitly specified null
*in the template*. They are coming from bean properties and return
values of Java methods.
If they come from the return value of a java method or a bean property
(which is usually just getFoo() return value) then it is a java null,
just as if it came from [#set foo = null]
Er... so what's then? It seems to be an irrelevant fact for me. What I
tried to point out is that if the template author enters "null" *into
the template*, then obviously he knows that he deals with a Java null,
and certainly he really wants to play with Java null-s here. But when
he just innocently accesses the data-model, it's not necessarily clear
for him at all.
The difference between the fact that user.middle_name is defined but
null and user.midle_name is just undefined is always going to be a
somewhat subtle distinction, I think. The goal of all this touch-up is
that, in the first case, you can have a null value that can be passed
around and into java API's, say, and in the second case, where it is
just a spelling mistake, you are alerted to it immediately.
Post by Daniel Dekany
Post by Jonathan Revusky
If it comes from a hash where the key/value pair was not put in
explicitly, then it is a missing value.
Post by Daniel Dekany
Post by Jonathan Revusky
and the undefined value, which is likely the result of a misspelled
variable name, should cause an exception.
As for what happens when you have a default value, it seems that,
probably, you should go to the default value if it's a true deliberate
null, but still blow up when it's truly undefined. Otherwise, what are
you saying? That we have this default value here just in case you
misspelt a variable, so that we can keep going? That obviously isn't the
purpose of a default value, is it?
The treatment of the parameter expressions in the macro call and how
the macro reacts to the actual parameter values are separate issues.
For example *as far as the macro call statement is concerned*, this
[#set x = null]
BUT the foo macro may will say that, "No thank you, I don't want a
null here. I wanted a title, and you have provided nothing. Because
null is just nothing as far as I'm concerned.".
Yes, but that error comes later, when the macro tries to dereference x
and expects a string, but gets a null. But no error occurs at the
point where the macro is invoked. Well, it does occur when the macro
is invoked if x is just undefined, but in the example above, x is not
undefined, it is defined, but null, the distinction we didn't have
before.
But if the macro can't handle that null parameter anyway, then what is
the point of allowing it to blow later?
The problem I see is that we cannot know, in the general case, whether
the macro handles the null via explicitly checking for it, or passing it
into a java method where null actually means something or whatever. We
can't know, so we pass it through. The fact that the macro _usually_
does not handle it is not enough.

Of course, one could introduce extra syntax to indicate that the
parameter must be non-null. OTOH, we don't even have the syntax to
indicate that a parameter is definitely a number, say, and just rely on
the fact that, when you pass in something that is not a number to
something that wants a number, it will fail at the point that you try to
do something numerical with it...

As things stand, we haven't introduced any extra syntax hardly for any
of this, just a null keyword (which many people would expect there to
be) and a ?is_null built-in.
Post by Daniel Dekany
Anyway there is no grantee
that it will blow at all. Like maybe it passes the null to another
macro that use a default value for its parameter, so the problem
remains hidden.
Well, as long as it's eventually dereferenced and causes an exception it
doesn't matter that much, since you get an execution trace and you can
find the origin of the problem. The problem is that there are cases
where, in many or most frequent paths of execution, the variable is
never dereferenced, so then the error gets undetected when it would be
if you alerted higher up. But, like I said, if it is a genuine,
deliberate FTL JAVA_NULL singleton, we can't know for sure whether
passing in the null is an error or not.
Post by Daniel Dekany
(So note that it's not entirely backward compatible
with 2.3.x templates: it may won't blow as I said, also it can upset
things that utilize #attempt/#recover. Admittedly these will not be
frequent... But also, in wrong templates many error message will be
less helpful with 2.4.) Now sure, we can't tell if the author of the
macro have considered the case of null, but in almost all cases he
will not.
Well, "almost all" is not good enough.
Post by Daniel Dekany
So for most cases the natural and conventional thing, or at
least the better thing would be if a null parameters blow early. And
we have this opportunity to do it this way in FTL, because it would be
backward compatible. (<OT>As I said, I would prefer if Java Language
works this way as well. Did I say that the parameter can be null? Then
why does it let them be that? Nobody else is sick of writing those
explicit null checks everywhere, and then also manually documenting
for each parameter if it can be null or not? This all could be
auto-generated, and also the number of hard-to-track-down NPE-s --
that are often caused by programmers forget or not willing to do null
checks -- would decrease.</OT>) And in the remaining cases -- which
will certainly be a minority -- the user can be explicit about it,
like marking the parameter as null bypasser or something. Well, that
was what I wanted to say about it. You guys better sleep on it before
making the final decision.
Post by Jonathan Revusky
(And with the same
Post by Daniel Dekany
logic a default parameter value step in action of the parameter value
is null.)
Okay, I am willing to agree with you on that point, assuming it is a
true java null, and not simply an undefined variable.
Yes, that's what I meant. (Theoretically this all happens in the
macro, not in the macro call statement, with other words, after the
parameter expression were already evaluated. So of course if there
were an undefined variable, it blows before the macro has chance to
apply defaults and like.)
I changed it to work your way, but again, only for a genuine JAVA_NULL,
not an undefined variable.

JR
Post by Daniel Dekany
[snip]
Daniel Dekany
2007-06-08 21:10:14 UTC
Permalink
Friday, June 8, 2007, 9:17:50 PM, Jonathan Revusky wrote:

[snip]
Post by Jonathan Revusky
Post by Daniel Dekany
less helpful with 2.4.) Now sure, we can't tell if the author of the
macro have considered the case of null, but in almost all cases he
will not.
Well, "almost all" is not good enough.
It's good enough if in those minority of cases one can explicitly
specify that the parameter can be Java null. It seems to me that you
sacrifice the best possible operation of the 95% of macros (where null
shouldn't be allowed) for the sake of the ease of usage in the case of
the 5% of macros (which are the macros where null parameter value
indeed should be allowed). Not a good business.
--
Best regards,
Daniel Dekany
Loading...