euddraft
euddraft copied to clipboard
Make `StringBuffer` to `object`.
We need to expand EUDStruct
to fully port current behavior of StringBuffer
and prevent performance regression.
Highly related to armoha/euddraft#58
Background
constructor
and constructor_static
object Obj {};
const staticObj = Obj(); // calls constructor_static and maybe constructor too
const dynamicObj = Obj.alloc(); // calls constructor
var objVar = globalStaticObj;
const globalObjFromCast = Obj.cast(objVar); // does not call any constructor
function foo(obj: Obj) {}
function afterTriggerExec() {
foo(objVar); // does not call any constructor
}
Default implementation of constructor_static
calls constructor
too, but user is free to override it to make specialized and separate code for static declaration:
class EUDStruct(ut.ExprProxy, metaclass=_EUDStruct_Metaclass):
# Constructor & Destructor of classes
def constructor(self):
"""Constructor for individual structures.
Default constructor accepts no arguments, but derived classes may
accept additional arguments.
This function is called when
- Argument is allocated from pool (self.isPooled = True)
- Argument is generated (self.isPooled = False)
You may choose to either allocate member from pool or just allocate
members statically via self.isPooled.
"""
pass
def constructor_static(self, *args, **kwargs):
"""Specialized constructor for static variables.
Static variable may not require allocation for member variables.
Function may specialize their behavior by overriding this function"""
self.constructor(*args, **kwargs)
def destructor(self):
"""Destructor for individual structures.
Destructor accepts no arguments. Destructor is called when
- Manually called. (Ex: stack variable)
- free() is called for object
"""
pass
Motivation
We want to pass StringBuffer
to function but we don't want to make StringBuffer
too slow.
StringBuffer.StringIndex
, .epd
and .capacity
should be static
-
.StringIndex
: map string idStringBuffer
uses -
.epd
: starting address of string content -
.capacity
: every string has fixed capacity and can't reallocate (Changing starting offset of string is not supported in StarCraft: Remastered. Starting addresses of every strings are fixed.)
It is breaking change to make var
field to const
or static
field. It is okay to change static
field to const
or var
field.
Field mutability
var
field
- Usual field, free to mutate.
const
field
- Similar to
const
, the field can't be reassigned once it's initialized. - example: CUnit fields of
UnitGroup
andEUDBag
(once it'sgroup.add(cunit)
ed, you can't further mutate.)
static
field
-
static
field access always happens in compile time whenobject
is known in compile time. No runtime cost. - Implementor must initialize every static fields in
constructor_static
. - Can't store EUDVariable in
static
field. -
Object.alloc
is not allowed whenObject
has any static field
# eudplib syntax to declare fields
class Obj(EUDStruct):
_fields_ = [
"varfield", # var field without type
("untyped_var_field", None), # equivalent code
("typed_var_field", EUDArray),
# new syntax below
("verbose_var_field", None, "var"),
("const_field", None, "const"),
("static_field", TrgUnit, "static"),
]
How to implement
EUDStruct.__init__
위에는
객체.cast(인스턴스)
하는거 (_from이 있을 때)
아래는 객체(인자)
정적 선언하는거 (else:)
- 목표:
constructor_static
에서static
필드를setattr
한 걸 모아서super(ExprProxy).__init__
에 사용하는EUDVArray
의 초기값으로 넣기
(maybe we need to use Forward()
?)
._initialized
-
._initialized == True
면인스턴스.필드 = 값;
을 하면VArray[필드인덱스] = 값
코드가 된다 (없는 필드를 대입하면 컴파일 오류) -
._initialized
가 없으면 일반적인 파이썬 코드처럼self.__dict__[필드] = 값
임
Q. allow mutations only within constructor_static
?
object ObjectWithStaticField {
static field_static;
function constructor_static() {
this.field_static = $U("Fenix (Zealot)");
// Q. constructor_static 안에서만 변경을 허용할지?
this.field_static *= 2; // 헷갈리니까 막는게 나을 거 같음
}
};
Q. optimize global object initialization?
object Obj {
var v;
const c;
static s;
function constructor_static() {
this.v = 1;
this.c = 2;
this.s = 3;
this.constructor(); // optional
}
};
const obj_global = Obj();
function beforeTriggerExec() {
const obj_local = Obj();
}
-
obj_global
은 1, 2, 3 대입하는 트리거를 만드는 대신에EUDVArray
의 초기값을[1, 2, 3]
으로 넣으면 좋을 듯 -
obj_local
은var
필드인.a
와const
필드인.b
에 1, 2 대입하는 트리거를 꼭 만들어야함
Q. change .constructor
, .constructor_static
and .destructor
to static methods in epScript? (No @EUDMethod
)
This will be breaking change that every constructors and destructors will duplicate codes, and users need to migrate to make separate methods and calling them on ctors and dtors to get previous behaviors.
Q. do we need static if
?
// we can write this in eudplib but can't in epScript
object Obj {
var a, b;
static s;
function constructor() {
if (this.isPooled) {
// this object is dynamically allocated with Obj.alloc();
} else {
// this object is statically allocated with Obj(arg);
}
}
function constructor_static(arg) {
if (py_isinstance(arg, py_str)) {
// arg is str
} else if (py_isinstance(arg, py_int)) {
// arg is int
}
this.constructor(); // optional
}
};
Actually I started to lose interest in making static
field as public API. It complicates the language but does not hold much weight. e.g. ancient version of Rust had immutable struct field but later dropped it.
It's mostly solved in euddraft 0.9.10.2.