Understanding OOP in Actionscript - apache-flex

A.as :
public class A {
public function getFunction():Function {
return function():void {
if(this is C) {
trace("C");
} else {
trace("not C");
}
}
}
public function func1():void {
var internalFunc:Function = getFunction();
internalFunc();
}
}
B.as :
public class B extends A implements C {
}
In some other class :
var b:B = new B();
B.func1();
Output is :
"Not C"
I was expecting the trace output to be
"C"
Can someone explain why?

An anonymous function, if called directly, is scoped to the global object. If you trace this inside it, you will see [object global] instead of [object B], as you would, if this refered to b.
A common workaround is using a closure:
var self:A = this;
return function():void {
if(self is C) {
trace("C");
} else {
trace("not C");
}
}
Please note however, the instance-members of a class defining an anonymous function are available from within. This works, because they are resolved at compile time.
edit in response to Amarghosh's question:
Yes, this points to the global object, but that doesn't mean, you cannot access the instance members of the declaring class. This little piece of code should explain the details:
package {
import flash.display.Sprite;
public class Test extends Sprite {
private var foo:String = "foo";
public function Test() {
var anonymous:Function = function ():void {
trace(foo);//foo
trace(this.foo);//undefined
};
anonymous();
}
}
}
greetz
back2dos

A few things with the code that I assume are just typos?
The getFunction() method doesn't return anything and will thus cause a compiler error.
Your call code calls func1() as a static method, not as a method on an instance of the B. This will also cause a compiler error. I believe these are typos.
In my tests, using your modified code. The output is C. There must be something else going on with your code. Here are my mods to A:
public function getFunction():Function {
if(this is C) {
trace("C");
} else {
trace("not C");
}
return getFunction;
}
Here is my mod to the runnable code, which I put in creationComplete of an empty MXML Application file:
var b:B = new B();
b.func1();
I assume your "real world" code is more extensive than the sample and there must be something else going on.

Related

Haxe: Binding pattern with abstract fields access methods

I'd like to make wrapper to implement simple data binding pattern -- while some data have been modified all registered handlers are got notified. I have started with this (for js target):
class Main {
public static function main() {
var target = new Some();
var binding = new Bindable(target);
binding.one = 5;
// binding.two = 0.12; // intentionally unset field
binding.three = []; // wrong type
binding.four = 'str'; // no such field in wrapped class
trace(binding.one, binding.two, binding.three, binding.four, binding.five);
// outputs: 5, null, [], str, null
trace(target.one, target.two, target.three);
// outputs: 5, null, []
}
}
class Some {
public var one:Int;
public var two:Float;
public var three:Bool;
public function new() {}
}
abstract Bindable<TClass>(TClass) {
public inline function new(source) { this = source; }
#:op(a.b) public function setField<T>(name:String, value:T) {
Reflect.setField(this, name, value);
// TODO notify handlers
return value;
}
#:op(a.b) public function getField<T>(name:String):T {
return cast Reflect.field(this, name);
}
}
So I have some frustrating issues: interface of wrapped object doesn't expose to wrapper, so there's no auto completion or strict type checking, some necessary attributes can be easily omitted or even misspelled.
Is it possible to fix my solution or should I better move to the macros?
I almost suggested here to open an issue regarding this problem. Because some time ago, there was a #:followWithAbstracts meta available for abstracts, which could be (or maybe was?) used to forward fields and call #:op(a.b) at the same time. But that's not really necessary, Haxe is powerful enough already.
abstract Binding<TClass>(TClass) {
public function new(source:TClass) { this = source; }
#:op(a.b) public function setField<T>(name:String, value:T) {
Reflect.setField(this, name, value);
// TODO notify handlers
trace("set: $name -> $value");
return value;
}
#:op(a.b) public function getField<T>(name:String):T {
trace("get: $name");
return cast Reflect.field(this, name);
}
}
#:forward
#:multiType
abstract Bindable<TClass>(TClass) {
public function new(source:TClass);
#:to function to(t:TClass) return new Binding(t);
}
We use here multiType abstract to forward fields, but resolved type is actually regular abstract. In effect, you have completion working and #:op(a.b) called at the same time.
You need #:forward meta on your abstract. However, this will not make auto-completion working unless you remove #:op(A.B) because it shadows forwarded fields.
EDIT: it seems that shadowing happened first time I added #:forward to your abstract, afterwards auto-completion worked just fine.

NativeActivity in XAML loaded COMPILED workflow throws Expression Activity type 'CSharpValue1' requires compilation in order to run

This is a know error when using C# expressions in windows workflow. The article at https://learn.microsoft.com/en-us/dotnet/framework/windows-workflow-foundation/csharp-expressions#CodeWorkflows explains the reason and how to fix it. It all works fine for me in standard workflows, but as soon as I add a custom NativeActivity to the WF, I get that same error again !
Below the code of how I load the XAML workflow and the simple NativeActivity (which is the ONLY activity in the test workflow and inside that activity is a simple assign expression).
Loading and invoking WF via XAML:
`XamlXmlReaderSettings settings = new XamlXmlReaderSettings()
{
LocalAssembly = GetContextAssembly()
};
XamlReader reader = reader = ActivityXamlServices.CreateReader(new XamlXmlReader(fileURL, settings));
ActivityXamlServicesSettings serviceSettings = new ActivityXamlServicesSettings
{
CompileExpressions = true
};
var activity = ActivityXamlServices.Load(reader, serviceSettings);
WorkflowInvoker.Invoke(activity);`
Doing it in code throws same Exception:
Variable<string> foo = new Variable<string>
{
Name = "Foo"
};
Activity activity = new Sequence
{
Variables = { foo },
Activities =
{
new TimeExecuteUntilAborted
{
Activities =
{
new Assign<string>
{
To = new CSharpReference<string>("Foo"),
Value = new CSharpValue<string>("new Random().Next(1, 101).ToString()")
}
}
}
}
};
CompileExpressions(activity);//the method from the article mentioned above
WorkflowInvoker.Invoke(activity);
The Native Activity:
[Designer("System.Activities.Core.Presentation.SequenceDesigner, System.Activities.Core.Presentation")]
public sealed class TimeExecuteUntilAborted : NativeActivity
{
private Sequence innerSequence = new Sequence();
[Browsable(false)]
public Collection<Activity> Activities
{
get
{
return innerSequence.Activities;
}
}
[Browsable(false)]
public Collection<Variable> Variables
{
get
{
return innerSequence.Variables;
}
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
metadata.AddImplementationChild(innerSequence);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(innerSequence);
}
}
Your TimeExecutedUntilAborted class seems to be the culprit. I was able to swap in one of my own template NativeActivities instead and your workflow executed fine with the expressions. I'm guessing that your class is causing an issue in the compiler method when it parses your code. I used this doc as an example for my NativeActivity: https://msdn.microsoft.com/en-us/library/system.activities.nativeactivity(v=vs.110).aspx.
Sizzle Finger's answer is no solution but pointed me into the right direction to simply check what is different. It came out that the simple call to the base class method was missing:
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata); // !! This needs to be added
metadata.AddImplementationChild(innerSequence);
}

Symfony2 OOP design

I'm facing a OOP design problem ... My goal is to build a Improvement system.
It is really simple to understand, here is the code sample :
<?php
interface Improvement {
public function getGains();
public function isActivated();
}
// tagged "improvement"
class AImprovement implements Improvement {
public function getGains() {
return 1;
}
public function isActivated() {
return true;
}
}
// tagged "improvement"
class BImprovement implements Improvement {
private $statsCenter;
public function __construct(StatsCenter $statsCenter) {
$this->statsCenter = $statsCenter;
}
public function getGains() {
return 10;
}
public function isActivated() {
return $statsCenter->getStats()['totalGains'] > 10;
}
}
class ImprovementCenter {
private $improvements;
public function addImprovement(Improvement $improvement) {
$this->improvements[] = $improvement;
}
public funtion getGainsSum() {
$s = 0;
foreach ($this->improvements as $improvement) {
$s += $improvement->getGains();
}
return $s;
}
}
class StatsCenter {
private $improvementCenter;
public function __construct(ImprovementCenter $improvementCenter) {
$this->improvementCenter = $improvementCenter;
}
public function getStats() {
return [
'totalGains' => Money::toEUR($this->improvementCenter->getGainsSum())
];
}
}
We can create x implementations of Improvement interface. If we tag them with "improvement" they will be added to the definition of ImprovementCenter with addMethodCall by calling addImprovement.
So, ImprovementCenter has a clear dependency on all the "improvement" tagged services.
And for some reason BImprovement is enabled only if the gains in euros > 10. ( Don't ask me why ).
But we can clearly see a circular dependency : BImprovement -> StatsCenter -> ImprovementCenter -> BImprovement ...
Any ideas on how to solve it ? (I already found some solution but I need more ideas). The side goal is also to benefits lazy services loading of symfony2, ImprovementCenter must be created only if it is injected somewhere.
Thank you !
EDIT :
Here is one dirty solution that I found. First the main problem is that here I have an observer pattern with Improvements as Observers. The consequence is that ImprovementCenter (the subject) depends on all its observers, that is not the pattern goal.
Then I moved the dependencies: I have kind of an ObserverManager that depends on ImprovementCenter and all Improvents, the ObserverManager manually do $improvementCenter->addImprovement($improvement).
Now the $improvementCenter has no dependency on Improvements.
The problem is that I must initialise ObserverManager on each kernelRequest, without that trick the ImprovementCenter will not have any Improvements linked as observers.
This solution perfectly works, but it smells kind of bad .. ahah
Ideas ?

Callable objects on ActionScript?

is it posible to have callable objects on ActionScript? For example:
class Foo extends EventDispatcher
{
Foo() { super(); }
call(world:String):String
{
return "Hello, " + world;
}
}
And later...
var foo:Foo = new Foo();
trace( foo("World!") ); // Will NOT work
Why would you need to do this? (I'm not criticising, just interested!) Functions in AS3 are themselves first-class citizens, and can be passed around as arguments.
e.g.
public function main(foo:Function):void
{
trace(foo("World!")); // Will work, assuming foo = function(str:String):String {...}
}
No, only functions/methods can be called in this way. If the only reason is you want to type fewer characters, then you should shorten the length of the instance names and method names.
One option is to use a closure:
public function Foo():Function {
var bar:String;
return function (world:String):String {
var msg:String;
if (bar) {
msg = bar + ' says "Hello, ' + world + '"';
} else {
msg = "Hello, " + world;
}
bar = world;
return msg;
}
}
...
var foo = Foo();
trace( foo("World!") );
This is a much simplified case of the larger pattern of implementing objects as functions. As such, it's more useful in languages that support FP but not OOP, but does technically give you a callable "object". The syntax may be a little off, but:
public function createFoo(barInit, ...):Function {
var slots = {
greeter: barInit, ...
};
var methods = {
'get': function(name) { return slots[name]; }
'set': function(name, value) { slots[name] = value; }
greet: function(whom) {
var msg = slots.greeter + ' says "Hello, ' + whom + '"'
slots.greeter = whom;
return msg;
},
...
};
return function (method:String):* {
args = Array.splice.call(arguments, 1);
return methods[method].apply(null, args);
}
}
var foo = createFoo('Kermit');
trace(foo('greet', "World"));
trace(foo('greet', "Sailor"));
You probably don't want to do it in AS.
As others had said, you can't have callable objects. However, if for some reason you want to have stateful functions, you can achieve it with help of static class variables and package level functions. For example:
// com/example/foo/Helper.as
package com.example.foo {
public class Helper {
private static var _instance:Foo;
public static var data:String;
public static function get instance():Helper
{
if(!_instance) { _instance = new Helper(); }
return _instance;
}
}
}
// com/example/foo/hello.as
package com.example.foo {
public function hello(world:String):void
{
if(Helper.instance.data)
{
trace("Bye, " + Helper.instance.data);
}
trace("Hello, " + world);
Helper.instance.data = world;
}
}
When used, it will print different things.
hello("World!"); // traces "Hello, World!"
hello("People"); // traces "Bye, World!" and "Hello, People"
note: both the constructor and the method declaration miss the keywords public function to even compile, but I suppose that's not the original code. :)
the answer is: you can't.
my question is: what do you want to accomplish?
Functions are the only callable values. And Functions are primitives in ActionScript, much as ints, or Booleans, so there is no meaningful way to extend them.
If you want it to be an object, do it the Java way, defining an ICallable interface, and actually call a method, or just really use a function. closures provide the most simple and flexible possibility to create stateful functions, if that is what you want.
edit: well, you can do this (as an example):
private var fooInst:Foo = new Foo();
protected var foo:Function = fooInst.call;
and then the following workst as you wish:
<mx:Label text="{foo('Whatever')}"/>
its maybe even a little more flexible, although you lose the benefits of strict typing.
greetz
back2dos

Dynamically implement interface in Groovy using invokeMethod

Groovy offers some really neat language features for dealing with and implementing Java interfaces, but I seem kind of stuck.
I want to dynamically implement an Interface on a Groovy class and intercept all method calls on that interface using GroovyInterceptable.invokeMethod. Here what I tried so far:
public interface TestInterface
{
public void doBla();
public String hello(String world);
}
import groovy.lang.GroovyInterceptable;
class GormInterfaceDispatcher implements GroovyInterceptable
{
def invokeMethod(String name, args) {
System.out.println ("Beginning $name with $args")
def metaMethod = metaClass.getMetaMethod(name, args)
def result = null
if(!metaMethod)
{
// Do something cool here with the method call
}
else
result = metaMethod.invoke(this, args)
System.out.println ("Completed $name")
return result
}
TestInterface getFromClosure()
{
// This works, but how do I get the method name from here?
// I find that even more elegant than using invokeMethod
return { Object[] args -> System.out.println "An unknown method called with $args" }.asType(TestInterface.class)
}
TestInterface getThisAsInterface()
{
// I'm using asType because I won't know the interfaces
// This returns null
return this.asType(TestInterface.class)
}
public static void main(String[] args)
{
def gid = new GormInterfaceDispatcher()
TestInterface ti = gid.getFromClosure()
assert ti != null
ti.doBla() // Works
TestInterface ti2 = gid.getThisAsInterface()
assert ti2 != null // Assertion failed
ti2.doBla()
}
}
Returning the Closure works fine, but I couldn't figure a way to find out the name of the method being called there.
Trying to make a Proxy to the this reference itself (so that method calls will call invokeMethod) returns null.
You could use the Map coercion feature of Groovy to dynamically generate a Map that represents the given interface:
TestInterface getMapAsInterface() {
def map = [:]
TestInterface.class.methods.each() { method ->
map."$method.name" = { Object[] args->
println "Called method ${method.name} with ${args}"
}
}
return map.asType(TestInterface.class)
}
To complete the response of Christoph, as stated by this page, you can implement an interface with a closure. For example:
def map = [doBla: { println 'Bla!'}, hello: {world -> "Hello $world".toString()}] as TestInterface
map.hello 'Groovy' // returns 'Hello Groovy'

Resources