回复:在类定义中将消息传递给“this”默认情况下,JMP 不提供直接查询伪命名空间(无论是 window、this、box 等)的好方法。
对于类,您可能会考虑创建一个用于构造类的包装器——然后该包装器可以创建实例生成器函数,并且在该实例生成期间,您可以为该类提供一个循环引用(请注意,这可能会导致内存泄漏) -- 确保您创建一个跟踪系统并在应该删除类时提供/调用删除器方法以删除循环引用等。
这是一个例子:
Names Default to Here( 1 );
New Namespace( "class" );
class:Get Init Args = Function( {_class},
{Default Local},
For( i = 1, i <= N Items( _class ), i++,
If( Head Name( Arg( _class, i ) ) == "Glue",
For( j = 1, j <= N Arg( Arg( _class, i ) ), j++,
If( As Name( Head Name( Arg( Arg( Arg( _class, i ), j ), 1 ) ) ) == As Name( "_create_" ),
Return( Arg( Arg( Arg( Arg( _class, i ), j ), 2 ), 1 ) )
)
)
)
);
Return( {} )
);
class:Define Class = Function( {_class},
{Default Local},
class = Expr( Define Class() );
Summation( i = 1, N Arg( _class ),
Insert Into( class, Arg( _class, i ) )
);
init args = class:Get Init Args( _class );
init redirects = Expr( __cl:_create_() );
Summation( i = 1, N Items( init args ),
If( Head Name( Arg( init args, i ) ) == "Assign",
Insert Into( init redirects, Eval Expr( Name Expr( Expr( Arg( Arg( init args, i ), 1 ) ) ) ) )
,
Insert Into( init redirects, Eval Expr( Name Expr( Expr( Arg( init args, i ) ) ) ) )
)
);
Eval( class );
ns = Namespace( "class" );
Eval( Substitute( Expr(
ns[__class__] = Function( __args__,
{__cl = New Object( __class__ )},
__cl:self = __cl;
__class_call__;
__cl
)
),
Expr( __class__ ), Arg( _class, 1 ),
Expr( __args__ ), init args,
Expr( __class_call__ ), Name Expr( init redirects )
) );
0
);
class:Define Class({
"example",
_init_ = Method( {}, 1 );
_create_ = Method( {assocArray},
For Each( {{key, setter}, _}, assocArray,
self << Insert( key, Eval Expr( Method( {value}, self:TrySetProperty( Expr( key ), value, Expr( setter ) ) ) ) )
)
);
Try Set Property = Method( {parameter, value, expression If Changed},
Match( value,
., ., //Do nothing if missing value
,
self[parameter], . //Do nothing if unchanged value
,
self[paremeter] = value; //Otherwise update the value
Eval( expression If Changed ); //and eval the expression
);
);
show = Function( {name},
show( name )
)
});
//show( namespace( "class" ) );
cls = class:example( ["A" => expr( self:show( "EXPLETIVE" ) ), "B" => Expr( thing 2 )] );
show( cls << get keys );请注意,尽管 JMP 类只是带有附加函数的美化命名空间(附加函数知道它们所在的命名空间的命名空间)。您可以只使用常规名称空间和元编程来做一些非常相似的事情。使用常规命名空间,JMP 不会抛出关于无法访问函数内的类方法等多余的错误。
在类定义中将消息传递给“this”是否可以从方法中将消息传递给类的实例?
这是我正在尝试做的一个例子:
Define Class(
"example",
x=1;
test = Method( {name, method},
<< Insert(name, method);
);
);
t = New Object( example());
// This fails to insert the blah method
t:test("blah", Method({y}, show("Blah " || char(x) || char(y))));
t:blah(6);
//This succeeds in inserting and calling the blah method
t << Insert("blah", Method({y}, show("Blah " || char(x) || char(y))));
t:blah(6);我怀疑我可能需要明确地写“this << Insert”,但这会产生不同的错误:
Define Class(
"example",
x=1;
test = Method( {name, method},
<STRONG>this << Insert(name, method);</STRONG>
);
);
t = New Object( example());
// This fails because "send expects scriptable object"
t:test("blah", Method({y}, show("Blah " || char(x) || char(y));));
t:blah(6);我还考虑过显式调用 Send(无法添加方法)和 this:Send(无法解析名称 Send)。
我还考虑过直接调用 this:Insert(无法解析名称 Insert)和 Insert(成功添加了 blah 方法,但未能正确探测调用机制,因此没有参数传递到方法中)。
动机:
我这样做是因为我试图为类属性列表自动创建 getter 和 setter 方法。理想情况下,我将能够做到以下几点:
Define Class(
"example",
_init_ = Method( {assocArray},
For Each({property, updateMethod}, assocArray,
Insert(key, Eval Expr(Method({value}, TrySetProperty(Expr(property), value, Expr(updateMethod)))));
);
);
TrySetProperty=Method({parameter, value, expressionIfChanged},
match(value,
., ., //Do nothing if missing value
this << Get Value(parameter), ., //Do nothing if unchanged value
this << Insert(parameter, value); //Otherwise update the value
Eval(expressionIfChanged); //and eval the expression
);
);
);
properties = Associative Array({{"prop1", Expr(ThingToDoOnUpdate1)},{"prop2", Expr(ThingToDoOnUpdate2)}});
t = New Object( example(properties));
高级统计建模自动化和脚本质量与工艺工程回复:在类定义中将消息传递给“this”这似乎确实是 JSL 强制您执行的解决方法。
有一种模仿编程语言称为“DreamBerd”,它取笑编程范例。这种解决方法与模仿语言处理类的方式非常相似,但设法变得更加复杂。
(并不是说这是你的错,这只是 JSL 限制的结果)。
https://github.com/TodePond/DreamBerd
班级您可以创建类,但您只能创建它们的一个实例。 这不应该影响大多数面向对象的程序员的工作方式。
class Player {
const var health = 10!
}
const var player1 = new Player()!
const var player2 = new Player()! //Error: Can't have more than one 'Player' instance!这是你可以这样做的方法:
class PlayerMaker {
function makePlayer() => {
class Player {
const var health = 10!
}
const const player = new Player()!
return player!
}
}
const const playerMaker = new PlayerMaker()!
const var player1 = playerMaker.makePlayer()!
const var player2 = playerMaker.makePlayer()!
回复:在类定义中将消息传递给“this”我认为这可以通过自定义消息传递更好地处理,但我真的找不到任何关于如何实际执行此操作的文档。据我所知,没有关于实现您自己的消息的信息。
回复:在类定义中将消息传递给“this”消息只是调用类的方法——从技术上讲,您不能通过消息调用带参数的函数,但由于 JSL 类中的方法是表达式,消息调用的结果是一个可调用函数。出于所有意图和目的,您可以通过消息调用类方法。
注意这条线显示(clx << 添加(cly));打电话给添加通过消息的方法。
Names Default To Here( 1 );
Define Class(
"complex",
real = 0;
imag = 0;
_init_ = Method( {a, b},
real = a;
imag = b;
);
Add = Method( {y},
PRINT( "ADDING" );
New Object( complex( real + y:real, imag + y:imag ) )
);
Sub = Method( {y},
New Object( complex( real - y:real, imag - y:imag ) )
);
Mul = Method( {y},
New Object( complex( real * y:real - imag * y:imag, imag * y:real + real * y:imag ) )
);
Div = Method( {y},
t = New Object( complex( 0, 0 ) );
mag2 = y:Magsq();
t:real = real * y:real + imag * y:imag;
t:imag = imag * y:real + real * y:imag;
t:real = t:real / mag2;
t:imag = t:imag / mag2;
t;
);
Magsq = Method( {},
real * real + imag * imag
);
Mag = Method( {},
Sqrt( real * real + imag * imag )
);
_to string_ = Method( {},
Char( real ) || " + " || Char( imag ) || "i"
);
_show_ = _to string_;
);
clx = New Object( complex( 1, 2 ) );
cly = New Object( complex( 2, 3 ) );
Show( clx << Add( cly ) );
clx << Delete;
cly << Delete;
Delete Classes( "complex" );回复:在类定义中将消息传递给“this”我一直忘记,虽然 JSL 借鉴了最好的(在这种情况下smalltalk中的消息传递), 它从来没有完全捕捉到原作的特别之处。