Static function inheritance in [incr Tcl] - oop

Inheritance in incr Tcl doesn't work as expected. Consider the code below.
package require Itcl
::itcl::class Base \
{
public {
proc function { } { puts "==== Base::function" }
}
}
::itcl::class Derived { inherit Base }
Base::function
Derived::function ;# FAILS
The last line fails, so Base::function is not inherited at Derived, though Derived inherits from Base.
Am I doing something wrong, or incr Tcl is designed to behave so?

Reading the docs I don't think that procs in an itcl class work the way you think they ought to:
proc name ?args? ?body?
Declares a proc called name. A proc is an ordinary procedure within
the class namespace. Unlike a method,
a proc is invoked without referring to
a specific object. When the proc body
is executed, it will have automatic
access only to common data members.
If the args list is specified, it establishes the usage information for
this proc. The body command can be
used to redefine the proc body, but
the args list must match this
specification.
Within the body of another class method or proc, a proc can be invoked
like any other command-simply by using
its name. In any other namespace
context, the proc is invoked using a
qualified name like "className::proc".
Procs in a base class that are
redefined in the current class, or
hidden by another base class, can also
be accessed via their qualified name.
My reading of this is that the proc is associated with it's class, it can be referred to in the derived class but it isn't defined in it. For example the following works:
package require Itcl
::itcl::class Base {
public {
proc function { } { puts "==== Base::function" }
}
}
::itcl::class Derived {
inherit Base
public {
proc function { } {
puts "==== Derived::function"
return [Base::function]
}
}
}
Base::function
Derived::function ;# FAILS

The proc you defined Base::function is (more or less) a regular proc in the namespace Base. When you inherit in Itcl, you just inherit methods, you don't inherit procs. In a related note, you cannot call the proc function from an instance of Base, you have to call it like any regular proc.
itcl::class Base {
public {
proc function { } { puts "==== Base::function" }
}
public method test {} {
$this function
}
public method test2 {} {
function
}
}
Base bb
bb test ;# yields error: bad option "function"
bb test2 ;# works as expected

Related

Making a custom declarator

Let's say I use a certain set of boilerplate fairly regularly:
class Foo {
method abc($a: $b, $c, +#d) is pure {
use Slang::Bar;
…
}
method xyz($a: $b, $c, +#d) is pure {
use Slang::Bar;
…
}
method blarg($a: $b, $c, +#d) is pure {
use Slang::Bar;
…
}
}
I'd rather be able to just say:
class Foo is/does Bar {
bar abc { … }
bar xyz { … }
bar blarg { … }
}
And somewhere in Bar, set up the declaration for bar (or, since class Foo will itself ultimately use its own declarator, it could go somewhere else and doesn't have to be pulled out in a separate Type). How would I go about doing that?
-1. Limitations (only for packages)
The method EXPORTHOW calls .set_how on current $?LANG adding a slang to the latter.
Then it add_package_declarator to the MAIN $?LANG which adds a package_declarator method to its Actions and Grammar. It is, I think, the only "dynamic slang" (in World.nqp).
If what you want is to overwrite routine_declarator. Then you have to write a slang imitating the chain just cited.
If you accept to keep the method keyword and make the automatic signature in the class, say according to the method name, here is a way:
Note: A Package is a container (package, grammar, module, role, knowhow, enum, class, subset). If you put code inside like a method, this gets executed (I'v just tried):
0. Description (EXPORTHOW)
I would use undocumented EXPORTHOW and DECLARE in a module because I did not find a way with Phaser. Apparently it is too late even at BEGIN.
The example I give, is decorating every method in a class (even BUILDALL).
1. Lib (decorator.rakumod)
class DecoratedClassHOW is Metamodel::ClassHOW {
method add_method(Mu $obj, $name, $code_obj) {
sub wrapper ($obj, $a, $b) {
say "Before $name";
my $res = $code_obj($obj, $a, $b);
say "After $name";
return $res;
}
my $res = callwith($obj, $name, &wrapper);
return $res;
}
}
my module EXPORTHOW {
package DECLARE {
constant decorated = DecoratedClassHOW;
}
}
2. Executable
use lib '.';
use decorator-lib;
decorated Foo {
method abc($a, $b) {
say "In abc: $a:$b";
}
}
my $f = Foo.new;
$f.abc(1, 2);
3. Output
Before BUILDALL
After BUILDALL
Before abc
In abc: 1:2
After abc
4. Sources
Grammar::Debugger: exporting a symbol (grammar) overriding find_method and add_method
And npq's NQPTraceHOW::trace-on: Looping with for $_.HOW.method_table($_) creating a new hash overwriting the method cache with the (well-named) nqp::setmethcache.
To automatize the signature, play with .signature
Jnthn article on EXPORTHOW
So post on EXPORTHOW impossible with role

Create Method via GDSL script that has a delegating closure parameter

Using the (scarcely documented) gdsl scripts of Intellij, one can add dynamic methods to a class:
contributor(context(ctype: "my.Type")) {
method name: "doIt", params: [body: {}], type: void
}
One can also configure the delegation of a closure:
contributor(context(scope: closureScope())) {
def call = enclosingCall("doIt")
if (call) {
def method = call.bind()
def clazz = method?.containingClass
if (clazz?.qualName == 'my.Type') {
delegatesTo(findClass('my.Inner'))
}
}
}
Which, when doIt is a method that is defined in the code (not dynamically added), also works as designed.
However, when using the closureScope with the previously created method, the containing class method is always null, meaning that I can not safely delegate inside the closure to the addressed my.Inner class.
What I want is adding a dynamic method equivalent to:
void doIt(#DelegatesTo(my.Inner) Closure)...
I.e. I want the method to be available in code completion (this works), and inside the so created closure, I want correct code completion when addressing methods of my.Inner.
So far, I tried various approaches:
include the #DelegatesTo annotation in the param definition
try more esoteric approaches in finding the owner of the closure, which fails because the GrMethodCall simply has no parent
unconditionally delegating all closures named doIt to my.Inner which works, but is no viable solution since I do have multiple doIt methods (on different classes) delegating to different targets.
So, how can I make IDEA behave as expected and delegate to the correct target?
Edit to make it clearer:
Given the following classes:
package my
class Type {
void doIt(Closure) {}
}
class Inner {
void inInner() {}
}
and the following gdsl:
contributor(context(scope: closureScope())) {
def call = enclosingCall("doIt")
if (call) {
def method = call.bind()
def clazz = method?.containingClass
println clazz?.qualName
if (clazz?.qualName == 'my.Type') {
delegatesTo(findClass('my.Inner'))
}
}
}
when I start typing in a new script:
new Type().doIt {
inInner()
}
When inside the closure, I get the following:
code completion for inInner
inInner is shown as valid
The console output when started with idea.bat from commandline shows the line my.Type (from the println)
Ctrl-B on inInner correctly links to source code.
(The same behaviour can be reached without the gdsl when annotation the Closure Parameter in the doIt method with #DelegatesTo(Inner))
However, I do not want to manually include the doIt method in the source of Type, it is generated by an AST Transformation, so my source file now looks like this:
package my
class Type {
}
class Inner {
void inInner() {}
}
I can tell IntelliJ about the new method using the following gdsl snippet
contributor(context(ctype: "my.Type")) {
method name: "doIt", params: [body: {}], type: void
}
Now the IDE correctly recognizes the doIt method with a closure parameter. However, inside the Closure, the following happens:
sometimes code completion shows inInner, sometimes after changing something, it does not (when using the original code to fix a type, it was shown, but later declared "unresolved", after going through the code changes of this edited example, it is not shown anymore...)
Even when shown, inInner is shown with "cannot resolve symbol" decoration
the console shows null as clazz, i.e. the method is found, but not linked to an owner ASTNode
Ctrl-B does not link to the corresponding method in Inner
So what I want is the same behaviour for an injected doIt method (via Gdsl) as with a method included in the source, i.e. I want the gdsl to inject a doIt method with a delegating closure (to Inner) into the type class.
This worked for me adding the ctype to scope insted of finding the class type from the method
contributor(context(scope: closureScope(), ctype: 'my.Type')) {
def call = enclosingCall("doIt")
if (call) {
delegatesTo(findClass('my.Inner'))
}
}

Describing a function parameter that takes a class as an argument in TypeScript

I want to write a function where you parse the class type (the class, not an instance) then the function will instantiate an instance based on that parameter.
This is best explained by example:
//All possible paramter types must inherit from this base class
class Base { public name : string = ''; }
//These are possible classes that could be parsed to the function
class Foo extends Base { constructor() { super(); console.log("Foo instance created"); } }
class Bar extends Base { constructor() { super(); console.log("Bar instance created"); } }
//This function should take a class that inherits from 'Base' as a paramter - then it will create an instance
function Example(param : ?????????) : Base //I don't know what type the 'param' should be
{
return new param(); //Create instance?? How do I do this
}
//This should be the output - if it worked (but it doesn't)
Example(Foo); //Logs "Foo instance created""
Example(Bar); //Logs "Foo instance created""
//So if this worked, it would become possible to do this:
let b : Foo = Example(Foo);
let c : Bar = Example(Bar);
So my questions is: what type would the param for the 'Example' function be? And how would I create an instance of param from within the function.
Note, if this question is a duplicate I apologise - but I don't know the technical name for this process so it is difficult to research.
You want something like this.
function Example<T extends Base>(param: new () => T): T {
return new param();
}
We know that you'll have some type that is a Base. We're going to name it T, and we'll say that T extends Base to enforce that.
We also know that param will construct a T with no parameters. We can write new () => T to describe that.
Basically the way to think about this is that a class has both an instance side and a static side (also called the "constructor" side). In your example, Base, Foo, and Bar on their own have the static side.
The static side for each of them consists of all the static members you specify (and there aren't any in this case), along with the construct signature. In your case, Example takes a constructor expects no arguments, and produces some subtype of Base.

To create an object (of some class) in a listener

I'm creating a script and have troubles.
Is it possible to create an object (of some class) from within a listener?
I tried it but I get an error: ``class not found''.
I want to do something like:
class ONE {
class_ONE_code
}
class TWO {
object o = alloc(ONE)
}
I need this to create a new listener when I execute another listener.
What you wish to do is certainly possible. Most likely you have a syntax error in your code. For example, your implementation of class TWO is invalid since a member variable like "o" cannot be initialized in the member declaration section of the class code. This can only be done within a class method, as illustrated in the example code below.
class One
{
void DoClassOneAction(Object self)
{
OKDialog("Class One action executed.");
}
}
class Two
{
Object oneInstance;
void DoClassTwoAction(Object self)
{
if (!oneInstance.ScriptObjectIsValid())
oneInstance = Alloc(One);
oneInstance.DoClassOneAction();
}
}
void main()
{
Object twoInstance = Alloc(Two);
twoInstance.DoClassTwoAction();
}
main();
Note that the coding requirements for DM script classes differ somewhat from those of other languages that support objects. You may want to review details in the Scripting > Objects section of the DM on-line help (accessed via Help > Search… menu item).

PHP Static and Normal Functions Calling [duplicate]

There are two distinct ways to access methods in PHP, but what's the difference?
$response->setParameter('foo', 'bar');
and
sfConfig::set('foo', 'bar');
I'm assuming -> (dash with greater than sign or chevron) is used for functions for variables, and :: (double colons) is used for functions for classes. Correct?
Is the => assignment operator only used to assign data within an array? Is this in contrast to the = assignment operator which is used to instantiate or modify a variable?
When the left part is an object instance, you use ->. Otherwise, you use ::.
This means that -> is mostly used to access instance members (though it can also be used to access static members, such usage is discouraged), while :: is usually used to access static members (though in a few special cases, it's used to access instance members).
In general, :: is used for scope resolution, and it may have either a class name, parent, self, or (in PHP 5.3) static to its left. parent refers to the scope of the superclass of the class where it's used; self refers to the scope of the class where it's used; static refers to the "called scope" (see late static bindings).
The rule is that a call with :: is an instance call if and only if:
the target method is not declared as static and
there is a compatible object context at the time of the call, meaning these must be true:
the call is made from a context where $this exists and
the class of $this is either the class of the method being called or a subclass of it.
Example:
class A {
public function func_instance() {
echo "in ", __METHOD__, "\n";
}
public function callDynamic() {
echo "in ", __METHOD__, "\n";
B::dyn();
}
}
class B extends A {
public static $prop_static = 'B::$prop_static value';
public $prop_instance = 'B::$prop_instance value';
public function func_instance() {
echo "in ", __METHOD__, "\n";
/* this is one exception where :: is required to access an
* instance member.
* The super implementation of func_instance is being
* accessed here */
parent::func_instance();
A::func_instance(); //same as the statement above
}
public static function func_static() {
echo "in ", __METHOD__, "\n";
}
public function __call($name, $arguments) {
echo "in dynamic $name (__call)", "\n";
}
public static function __callStatic($name, $arguments) {
echo "in dynamic $name (__callStatic)", "\n";
}
}
echo 'B::$prop_static: ', B::$prop_static, "\n";
echo 'B::func_static(): ', B::func_static(), "\n";
$a = new A;
$b = new B;
echo '$b->prop_instance: ', $b->prop_instance, "\n";
//not recommended (static method called as instance method):
echo '$b->func_static(): ', $b->func_static(), "\n";
echo '$b->func_instance():', "\n", $b->func_instance(), "\n";
/* This is more tricky
* in the first case, a static call is made because $this is an
* instance of A, so B::dyn() is a method of an incompatible class
*/
echo '$a->dyn():', "\n", $a->callDynamic(), "\n";
/* in this case, an instance call is made because $this is an
* instance of B (despite the fact we are in a method of A), so
* B::dyn() is a method of a compatible class (namely, it's the
* same class as the object's)
*/
echo '$b->dyn():', "\n", $b->callDynamic(), "\n";
Output:
B::$prop_static: B::$prop_static value
B::func_static(): in B::func_static
$b->prop_instance: B::$prop_instance value
$b->func_static(): in B::func_static
$b->func_instance():
in B::func_instance
in A::func_instance
in A::func_instance
$a->dyn():
in A::callDynamic
in dynamic dyn (__callStatic)
$b->dyn():
in A::callDynamic
in dynamic dyn (__call)
:: is used in static context, ie. when some method or property is declared as static:
class Math {
public static function sin($angle) {
return ...;
}
}
$result = Math::sin(123);
Also, the :: operator (the Scope Resolution Operator, a.k.a Paamayim Nekudotayim) is used in dynamic context when you invoke a method/property of a parent class:
class Rectangle {
protected $x, $y;
public function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
}
class Square extends Rectangle {
public function __construct($x) {
parent::__construct($x, $x);
}
}
-> is used in dynamic context, ie. when you deal with some instance of some class:
class Hello {
public function say() {
echo 'hello!';
}
}
$h = new Hello();
$h->say();
By the way: I don't think that using Symfony is a good idea when you don't have any OOP experience.
Actually by this symbol we can call a class method that is static and not be dependent on other initialization...
class Test {
public $name;
public function __construct() {
$this->name = 'Mrinmoy Ghoshal';
}
public static function doWrite($name) {
print 'Hello '.$name;
}
public function write() {
print $this->name;
}
}
Here the doWrite() function is not dependent on any other method or variable, and it is a static method. That's why we can call this method by this operator without initializing the object of this class.
Test::doWrite('Mrinmoy');
// Output: Hello Mrinmoy.
But if you want to call the write method in this way, it will generate an error because it is dependent on initialization.
The => operator is used to assign key-value pairs in an associative array. For example:
$fruits = array(
'Apple' => 'Red',
'Banana' => 'Yellow'
);
It's meaning is similar in the foreach statement:
foreach ($fruits as $fruit => $color)
echo "$fruit is $color in color.";
The difference between static and instantiated methods and properties seem to be one of the biggest obstacles to those just starting out with OOP PHP in PHP 5.
The double colon operator (which is called the Paamayim Nekudotayim from Hebrew - trivia) is used when calling an object or property from a static context. This means an instance of the object has not been created yet.
The arrow operator, conversely, calls methods or properties that from a reference of an instance of the object.
Static methods can be especially useful in object models that are linked to a database for create and delete methods, since you can set the return value to the inserted table id and then use the constructor to instantiate the object by the row id.
Yes, I just hit my first 'PHP Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM'. My bad, I had a $instance::method() that should have been $instance->method(). Silly me.
The odd thing is that this still works just fine on my local machine (running PHP 5.3.8) - nothing, not even a warning with error_reporting = E_ALL - but not at all on the test server, there it just explodes with a syntax error and a white screen in the browser. Since PHP logging was turned off at the test machine, and the hosting company was too busy to turn it on, it was not too obvious.
So, word of warning: apparently, some PHP installations will let you use a $instance::method(), while others don't.
If anybody can expand on why that is, please do.