Open x87 opened 4 years ago
method could be conditional:
class Actor
inAnyCar()
00DF: actor self in_any_car
end
end
var
0@: Actor
end
if
0@.InAnyCar()
then
gets compiled as
if
00DF: actor 0@ in_any_car
then
If the method is a template that simply gets inserted in-place of a call statement (see Design choices in the first post) you can not put anything except conditional opcodes in a method to be able to use it in the conditional expression. i.e. this would not be allowed:
class Math
isZero(x)
if
x == 0
then
0485: return_true
else
059A: return_false
end
end
end
if
Math.isZero(1) // false
then
It's unclear how to work with returning a value from the methods, i.e consider:
class Actor
pos()
00A0: store_actor self position_to x y z
end
how to represent x
, y
, z
in the code?
1) pass variables into the method as parameters
pos(x, y, z)
00A0: store_actor self position_to x y z
end
0@.pos(1@, 2@, 3@) // 00A0: store_actor 0@ position_to 1@ 2@ 3@
always having to pass a variable to store a result into can be tedious for simple cases like:
sqr(x, result)
0A90: result = x * x
end
one would want to simply have
class Math
sqr(x)
0A90: result = x * x
end
end
0@ = Math.sqr(2)
2) add an implicit variable result
then will represent the left side of the call expression:
pos()
00A0: store_actor self position_to result[0] result[1] result[2] // variant 1
00A0: store_actor self position_to result.0 result.1 result.2 // variant 2
end
then
( 1@, 2@, 3@ ) = 0@.pos() // 00A0: store_actor 0@ position_to 1@ 2@ 3@
this adds a lot of unusual syntax into the language.
3) combine both approaches, i.e. have an implicit result
for a single value and pass variables into the method for multiple values:
class Math
sqr(x)
0A90: result = x * x
end
pi(int, frac)
int = 3
frac = .14
end
end
0@ = Math.sqr(2) // 0@ = 4
Math.pi(1@, 2@) // 1@ = 3, 2@ = .14
Powerful! The question is: will the compiler pick up the declared classes if they are described in another file and were included via the {$i}
directive. There are plans to write such classes (I already have everything ready for this) and I would like to save the developer from copying everything every time.
I also wanted to ask: will it be possible to add constants to a class? Like this
class Draw
const MaxWidth = 640.0
end
//
0@ > Draw.MaxWidth
@wmysterio yes, the compiler definitely should be able to read class declarations from imported files.
static class variables could be a nice feature! Will keep that in mind.
Class instances should support inline declaration similar to primitive types:
int x = 0
Player p = Player.Create(x, 10.0, 20.0, -100.0)
todo: update this proposal after #263
2024 Draft
class Car
/// Directly mapped to command CREATE_CAR
/// Function and Command signatures must match
Create<0x00A5>(modelId: int, x: float, y: float, z: float): Car
/// Update is an instance method
Update(self: Car, flag: int)
// update
end
/// Can return logical values
Check(self: Car): logical
return true
end
end
Car c = Car.Create(#INFERNUS, 0, 0, 0) // compiled as 00A5
if c.Check() // compiled as a scm function
then
c.Update(1) // compiled as a scm function
end
Class Syntax
Here is the proposal to add a new syntax for defining custom classes in scripts. They may eventually become a replacement for static classes in the classes.db.
Let's take a look at an example:
Here we defined a class named
Actor
that has one methodputInCar
in.putInCar
method has one parametercar
. Then we declared a variable0@
of the typeActor
and finally called methodputInCar
on that class instance.Important Notes
0@.putInCar($car)
no code was produced in this script.self
that represents the class instance the method is called on. in this case it is the variable0@
0@.putInCar($car)
gets compiled into036A: put_actor 0@ in_car $car
Design Choices
when there is a method call statement the compiler takes the method body and replaces the statement with the entire body. it means the method could have many instructions and possibly even labels and they will be put in place of the call statement. in this sense class method are more templates than functions as in the other languages.
this however does not prevent local variables from being altered inside the method body. it means there is no separate scope created when the class method is called and if you, for example, change the variable 0@ in the class method it will be a side-effect for the caller:
There are a few possible choices to this dilemma:
1) leave it as is, considering this a liberate language design decision (when you invoke subroutines with
gosub
they could alter local scope as well) 2) forbid using local variables syntax inside methods. only use arguments passed into the method. this could be inconvenient if you need to keep a local state. 3) add extra prologue and epilogue before and after each method call that will store and restore all local variables. this adds extra overhead in runtime 4) use CLEO's scm_function that basically does # 3. this adds unnecessary dependency on CLEO.