Decorators are one of the most unusual features of Python. It is a tool that can only exist fully in a dynamically typed, interpreted language. In the first part of the article, my friendWitcher136 showed how to implement in C ++ the most approximate to the standard (Python) version of decorators.
I'll tell you about how I decided to try to implement decorators in a compiled programming language , for which I ended up writing my own small Haskell compiler based on LLVM .
Table of contents
How decorators work in Python
Before diving into the decorator compilation algorithm, let's talk about the implementation of decorators in python, and why it cannot be reproduced in the same form in a compiled language. I note right away that in this article, python is understood as CPython. All engine compartment parts refer only to it.
, , , , — , .
Python, - , :
decorator, func, old. new — old
def decorator(func):
def new(*args, **kwargs):
print('Hey!')
return func(*args, **kwargs)
return new
@decorator
def old():
pass
# old() "Hey!" - old new
— , -, — , .
Python-. , - — , , , . , , , — - "" .
, , , — - "" . : BINARY_SUBSTRACT () TypeError, 1 'a'. , STORE_FAST ( ), , , TypeError, .. STORE_FAST — .
, new — . -, , , decorator old.
1. —
. decorator , :
name = input(' ')
def first(func):
... #
def second (func):
... #
if name == 'first':
decorator = first
elif name == 'second':
decorator = second
else:
decorator = lambda f: f #
@decorator
def old():
pass
, old . (, C++) , (- ), . Python — , , , " ", .
, , old void-, , — , , , .
, Python, : .
2. Python
def decorator(func):
def two_args(x, y):
...
return two_args
@decorator
def one_arg(x):
...
, . one_arg , ( ) — , , , (, "" ). , ? " " . , , decorator -, .
, , , — . , .
— — func? , , — , . func A, A. void* func, , .
— func , — Witcher136 . , (. C++ ).
. :
- — ?
- — ?
- , , ( )
, Python — . , — Python — .
— " ", , , . , .
.
Haskell LLVM —
Haskell, , LLVM . Haskell llvm-hs, LLVM. Parsec, , - ( , , Parsec — parser combinators).
Grit — expression-oriented ()
Grit, , if-else, , — , .
int main() = {
int i = 0;
i = i + if(someFunction() > 0) {
1;
}
else {
0;
};
};
, i
1, someFunction , , 0 .
return
, ( ) .
, — , Grit, — , . returns
, — , ;
.
, , "" — "", — , .
int simple(int x) = {
/*
x y
*/
int y = someOtherFunction();
x + y;
};
/*
, , .
,
*/
int incr(int x) = x + 1;
int main() returns statusCode {
/*
returns
,
.
""
,
*/
int statusCode = 0;
int result = someFunction();
if (someFunction < 0) {
statusCode = 1;
};
};
Auto — Grit
Grit auto
, , ( ) .
— , . — — , — ..
, , returns
.
auto half (int x) = x / 2; // incr float
(expression-oriented), return
( — ) — Grit. , .
, , .
— ?
?
, , — runtime compile-time, .
, , , — , .
-, Grit — , ( AST, abstract syntax tree), . -, , .
, :
@auto flatten = {
auto result = @target;
if (result < 0) {
0;
}
else {
result;
};
};
, , 0, 0, .
@auto flatten
— flatten
@auto
— , (@ — , , ).
. , — , , , .
— @target
. , . ( ), , , , ( ).
, AST @target
, . , , — . , .
, Grit, — , Python.
, :
@auto lockFunction = {
mutex.lock();
@target
};
, - :
@auto optional = if (checkCondition()) {
@target;
}
else {
someDefaultValue;
};
Grit :
@auto flatten = {
auto result = @target;
if (result < 0) {
0;
}
else {
result;
};
};
@flatten
int incr(int x) = x+1;
flatten , .
"" , - :
Decorator "flatten" auto {
BinaryOp = (Def auto "result") (DecoratorTarget)
If (BinaryOp < (Var "result") (Int 0)) {
Int 0
}
else {
Var "result"
}
}
Function "incr" int ; args [Def int "x"] ; modifiers [Decorator "flatten"] ; returns Nothing {
BinaryOp + (Var "x") (Int 1)
}
, — Decorator
, incr
, Decorator "flatten"
. DecoratorTarget
— incr
.
, — . , , , "" — , .
, :
Function (int -> int) incr ["x"] {
BinaryOp i= (Def int "result") (
Block int {
BinaryOp i+ (Var int "x") (int 1)
}
)
If int (BinaryOp b< (Var int "result") (int 0)) {
int 0
}
else {
Var int "result"
}
}
:
- — AST, .
-
incr
— ,flatten
,DecoratorTarget
Block {...}
— " ", . , , —int "result"
.BinaryOp i=
int-,result
auto
— , , .
, , , . Python, , , Grit.
, — , , :
@auto lockF(mutex M) {
M.lock();
@target;
};
@lockF()
int someFunction(...)
— mutex M
, ""
, (, , Python — ).
, @args
, , " " . , @args.length
— , @args.1
— . - , - — .
, Haskell , , , , . , ( , ), - .
PS It was a very interesting and unusual experience for me - I hope that you too were able to learn something useful from this story. If you need a separate article about writing a LLVM-based Haskell compiler - write in the comments.
I will try to answer any questions in the comments, or in a telegram - @ nu11_pointer_exception