Skip to content

Default parameters on async functions do not work in Safari #881

Open
@JGreenlee

Description

@JGreenlee

Consider these two functions.

def multiply(a, b=1):
    return a * b


async def multiply_async(a, b=1):
    return a * b

Compiled to JS, they are:

// Transcrypt'ed from Python, 2024-09-01 01:05:45
import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, _sort, abs, all, any, assert, bin, bool, bytearray, bytes, callable, chr, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, hex, input, int, isinstance, issubclass, len, list, map, max, min, object, oct, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js';
var __name__ = '__main__';
export var multiply = function (a, b) {
	if (typeof b == 'undefined' || (b != null && b.hasOwnProperty ("__kwargtrans__"))) {;
		var b = 1;
	};
	return a * b;
};
export var multiply_async = async function (a, b) {
	if (typeof b == 'undefined' || (b != null && b.hasOwnProperty ("__kwargtrans__"))) {;
		var b = 1;
	};
	return a * b;
};

Now, let's test those 2 functions:

console.log('multiply')
console.log(multiply(5, 2))
console.log(multiply(5))

console.log('multiply_async:')
multiply_async(5, 2).then(console.log)
multiply_async(5).then(console.log)

In Chrome and Node, the output is:

multiply:
10
5
multiply_async:
10
5

But in Safari, the output is:

multiply:
10
5
multiply_async:
5
5

This is due to redeclaring b (var b = 1;), when b was already defined as the parameter of the function. In normal written Javascript, we would just reassign (b = 1).

Someone else has noticed this before:
https://medium.com/@alsotang/a-hoisting-bug-in-the-async-function-in-safari-ba1ecc386b4a

Therefore, it is not safe to re-declare function parameters using var

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions