The Draconic scripting language, designed to allow a safe in-memory runtime for user scripting with bindings to native APIs hosted in the parent application.
Requires Python 3.8+.
The Draconic language is based on, and implemented in, the CPython implementation of the Python language. However, there are a number of notable differences between Draconic and Python:
In Python, in-place operators (e.g. a += 1) are handled differently from binary operators and assignments (
e.g. a = a + 1). In Draconic, all in-place operators are unfurled to their binary-operator equivalent. In most cases
this does not create a semantic difference, except in the following cases:
Python
>>> a = {"a": 1, "b": 2}
>>> b = {"b": 3, "c": 4}
>>> a_reference = a
>>> a |= b
>>> a
{"a": 1, "b": 3, "c": 4}
>>> a_reference
{"a": 1, "b": 3, "c": 4}
>>> a is a_reference
TrueDraconic
>>> a = {"a": 1, "b": 2}
>>> b = {"b": 3, "c": 4}
>>> a_reference = a
>>> a |= b
>>> a
{"a": 1, "b": 3, "c": 4}
>>> a_reference
{"a": 1, "b": 2}
>>> a is a_reference
FalseUse dict.update() or set.update() instead for an in-place operation.
Python
>>> a = 1
>>> def incr_locally():
... a += 1
... return a
>>> incr_locally()
UnboundLocalError: local variable 'a' referenced before assignmentDraconic
>>> a = 1
>>> def incr_locally():
... a += 1
... return a
>>> incr_locally()
2While Python checks that all bindings in a pattern matching case with multiple options are the same across all branches, Draconic does not do any such check.
Python
>>> a = 1
>>> match a:
... case (1 as one) | (2 as two):
... print(one)
SyntaxError: alternative patterns bind different namesDraconic
>>> a = 1
>>> match a:
... case (1 as one) | (2 as two):
... print(one)
1As access to __dunder__ attributes is not allowed in Draconic, the function.__name__ and function.__doc__
attributes are exposed as function.name and function.doc instead.
Python
>>> def foo():
... """I am foo"""
... pass
>>> print(foo.__name__)
foo
>>> print(foo.__doc__)
I am fooDraconic
>>> def foo():
... """I am foo"""
... pass
>>> print(foo.name)
foo
>>> print(foo.doc)
I am foo