Open denis-migdal opened 1 year ago
One way to fix the function return type in Brython => JS callbacks, is to build functions in a way that implicit or empty return, returns an *internal()** temporary special value : e.g. <ImplReturn>
.
(*) This means that Brython users will never see or access this value. It'll be just used internally to track implicit returns.
Then :
<ImplReturn>
, replace it by None
.<ImplReturn>
replace it by undefined
.Then, we could have None
being implemented as null
*, which would remove the need to warn the user when trying to give None
to JS.
(*) It was almost the case before, but couldn't due to non-returning function having their return values converted to null
.
This could be implemented in several ways :
bind()
by an anonymous function checking the return type (Brython). BUT this costs a comparison at each return value.undefined
(JS) and the anonymous function replacing bind()
would give None
. BUT this costs an extra-parameter at each call. Should be more performant compared to previous solution.xxx.ImplRetVal
being equal to None
. When being called, put this value inside a local variable ImplRetVal
and put the property xxx.ImplRetVal
back to None
(could be removed by transpiler if no explicit return or empty return are detecting inside the function). Then upon implicit or empty return, returns this value. Then, in JS wrapper, when calling the function, setting its ImplRetVal
to undefined
before calling the wrapped brython function. This should be more performant than the 2 previous solutions with little to no overcost in Brython BUT would not support functions returning another function return value.. But that should cover 99% of cases. If you do return foo()
, you should expect a value, therefore None
/null
.I think solution (c) might be a good solution. The browser should be able to optimize the local variable, hence the only cost is accessing to the stored return value. I'd argue that the cost of it should be very little compared to the frame and parameters management made at each function calls.
In the commit referenced above I have implemented javascript.NULL == javascript.UNDEFINED
(Javascript is an endless source of surprises...)
I agree that there should be no "magic" conversion between None
, null
and undefined
. I have no clear opinion at the moment if we should warn when None
is passed to JS - perhaps mark it as deprecated ? But can we exclude use cases when we really want to pass None
to a JS function ?
For the rest of your comments, there is something I don't get: you seem to assume that the developer doesn't know whether non_returning_function
is a Brython function or a Javascript function. I think in the contrary that he actually knows where the function comes from, and
if(result === undefined)
in Javascript and if result is UNDEFINED
in Brython.if result is None
in Brython and if(result === __BRYTHON__.builtins.None)
in Javascript.Am I missing something ?
In the commit referenced above I have implemented
javascript.NULL == javascript.UNDEFINED
(Javascript is an endless source of surprises...)
Yeah, JS is a very dirty language.
Wait until you see that {}+[]
is 0 but []+{}
is an object xD.
In JS, ==
is when object has the same value after conversions/castings, meaning, that e.g. "" == false
is true.
When ===
is for a more strict comparaison, without conversions/castings, e.g. "" === false
is false.
For values (sémantiques de valeurs), ===
is true
when they have the same value, while for objects (sémantiques d'entités) it is true
when they are the same reference.
For the rest of your comments, there is something I don't get: you seem to assume that the developer doesn't know whether
non_returning_function
is a Brython function or a Javascript function. I think in the contrary that he actually knows where the function comes from
When you work with callbacks, you can't be sure of the origin of the callback, or controls what the called function will do with the callback.
For exemple, if we use a JS function (e.g. in a library) and give him a callback :
function foo( callback ) {
if( callback() ) {
console.log('returned true');
}
}
def callback()
pass
If the callback returns None
, the condition will be evaluated to true
, when it should be evaluated to false
for a non-returning function.
As null
and undefined
doesn't exists in Python, why not "hiding" their existence to Brython users ?
null
and undefined
doesn't exists in Brython, for Brython users, it only exists internally.None
symbol would be internally represented as null
undefined
<null>
and <undefined>
would exactly behave like None
.
null
and undefined
symbols is"hidden" to Brython users.<null> == <undefined>
and <null> is <undefined>
would both be true
, because they'd both be None
for Brython users. Meaning it'll be used as <value that is null or undefined> is None
equals true
.Meaning that return None
internally returns null
and return
internally returns undefined
.
Then for more control, only and only when wanting more control with JS/Brython interactions we could provide :
javascript.isNoneNull(<null or undefined>)
and javascript.isNoneUndefined(<null or undefined>)
, that'd be the only way (at the exception of console.log()
) to know whether the object is internally null
or undefined
. Used to process data comming from JS (and only for that).javascript.NoneNull
and javascript.NoneUndefined
to be able to explicitly get an internal null
or undefined
value before giving them to JS (and only for that).But this shouldn't be used by Brython users except in the very specific cases of interacting with JS : in python, there is no null
or undefined
, only None
. So Brython users, except when wanting explicit interactions with JS shouldn't even know they are 2 things. As <null> is <undefined>
in Brython, javascript.NoneNull is javascript.NoneUndefined
would also be true (because they are <null>
and <undefined>
.
The naming enables to insist that they are None
.
Keep 3 internal values :
undefined
null
None
(like an "undecided" between undefined
and null
).BUT
null
and undefined
doesn't exists in Brython, for Brython users, it only exists internally.None
symbol is internally None
undefined
(or could be also None
).null is undefined
, null is None
, undefined is None
: they are the same thing as they don't exists in Brython.<null>
and <undefined>
would exactly behave like None
.
null
and undefined
symbols is"hidden" to Brython users.null
and undefined
can be exchanged between JS and Brython without needing conversions.None
value raises an exception when given to JS : you have to first convert it either to internal null
or undefined
.javascript.enforceNoneNull(val)
or javascript.enforceNoneUndefined(val)
: returns null
or undefined
. Like a kind of "conversion" before giving it to JS.javascript.checkIfNoneNull(val)
and javascript.checkIfNoneUndefined(val)
: when processing the result of a JS function.The naming enables to insist that they are None
.
Hi,
In JS we have :
It means that
null
andundefined
are the same values, but are "different". In Python, I assume thatis
is more or less equivalent to===
:Therefore I think that in Brython we should have :
We could also assume that
None
has the same value asnull
andundefined
, but is different. This would help solving the following issues :JS functions returns
undefined
, while Python function returnsNone
, which might cause issues :instead we could have :
The same, when accessing to some JS values, have
null == None
could be expected, and would be coherent asundefined == null
.I do not think such behavior should produce unexpected side effect as :
is
usage is advise in Python when usingNone
. So every existing comparisons should be usingNone
, and thus having strong insurance about the real value.==
could be used specifically in Brython, to help not being too bothered byundefined
andnull
in trivial cases.For conversions between Brython <=> Javascript :
console.warn()
with a python trace.Indeed, giving a
None
to Javascript could be dangerous, e.g. if it expectsundefined
for a callback return value.Hence the need to warn the user. The behavior could be controlled through an option given to Brython (e.g.
NONE_CONVERSION
) :Cordially,