I need to prevent class A from being instantiated anywhere but only from another class B, then class B can return the created instance of class A which can be used in any other class.
I understand that B could be a Factory in this example, I looked in the factory pattern in the Haxe code cookbook but it does not seem suit what I am looking for.
In my example class B is doing some work then should return the result in an instance of class A.
no one should be able to create an instance of class A because it is the result of the work that class B performs. anyone needs an instance of A should ask B to do the work and return the resulted A instance
hope I explained it clearly
You would usually do this by using #:allow() metadata in combination with a private constructor:
A.hx:
class A {
#:allow(B)
private function new() {}
}
B.hx:
class B {
public static function create():A {
return new A(); // compiles
}
}
Trying to instantiate A outside of B will result in a compiler error:
class Main {
static function main() {
new A(); // Cannot access private constructor of A
}
}
Note that it's still possible to work around this by using #:access() or #:privateAccess metadata - in Haxe, nothing is ever truly private. It follows a philosophy of "the programmer knows best", which can be very powerful.
Also, you might want to declare A as #:final so nothing can subclass it, because subclasses can access private fields in Haxe. But again, this can be overriden with #:hack metadata.
Related
I have two immutable groovy classes that have a few shared values that I'm trying to abstract to a parent class. However when I create the following, the second test case always fails. Although everything compiles correctly and no error is thrown at runtime, when I assign the parent property int he constructor, it is never set, resulting in a null value. I havent found any documentation that forbids this, but I'm wondering is this even possible? I've tried a number of configuration of Annotations and class-types (e.g. removing abstract from the parent) but nothing seems to work short of just removing the #Immutable tag altogether.
abstract class TestParent {
String parentProperty1
}
#ToString(includeNames = true)
#Immutable
class TestChild extends TestParent {
String childProperty1
String childProperty2
}
class TestCase {
#Test
void TestOne() {
TestChild testChild = new TestChild(
childProperty1: "childOne",
childProperty2: "childTwo",
parentProperty1: "parentOne"
)
assert testChild
assert testChild.parentProperty1
}
}
Based on the code for the ImmutableASTTransformation, the Map-arg constructor added by the createConstructorMapCommon method does not include a call to super(args) in the method body.
which means that immutable classes are self contained by default
Now if you want to do it you need to use composition instead of inheritance and this is an example of how you can do it :
import groovy.transform.*
#TupleConstructor
class A {
String a
}
#Immutable(knownImmutableClasses=[A])
class B {
#Delegate A base
String b
}
def b = new B(base: new A("a"), b: "b")
assert b.a
i hope this will help :)
class Base, and class Ext extends Base.
class B<T> with typed method foo<T>(value:T)
Why B<Base>.foo doest not accept instance of B<Ext> (implicit downcast of the type parameter?) by default?
Here is an example
http://try.haxe.org/#d443f
class Test {
static function main() {
var bExt = new B(new Ext());
var bBase = new B(new Base());
bBase.foo(bExt);
//ofc
//bBase.foo(cast bExt);
}
}
class B<T>
{
public function new(v:T)
{
}
public function foo(v:B<T>)
{
//
}
}
class Base {
public function new(){}
}
class Ext extends Base {
public function new(){
super();
}
}
Is there any way to trigger implicit cast of the type parameter for B.foo?
There are three ways to interpret and answer your question:
1. foo(v:B<T>):
This is your example and it doesn't compile because T isn't allowed to be be variant. It happens because of the very existence of foo and because allowing bBase.foo(bExt), that is, unifying bExt with bBase, will then allow bBaseOfbExt.foo(bBase).
It is the fact that foo exists and that it can potentially modify the type that makes the bExt unification with bBase unsafe; you can see a similar (but maybe clearer) explanation in the manual, using arrays: type system – variance.
2. foo(v:T):
This is closer to what's on the body of your question (but not in the example) and it works fine.
3. foo<A>(v:B<A>):
Finally, if you have a type parameterized method, it also works, but you'd probably face other variance issues elsewhere.
This is just a very basic example of what I want to do. There's a bit more that goes on in the foobar method, but it's the gist of what I'm doing. It obviously doesn't work, since it fails to compile, but I'm wondering if I'm just passing the class incorrectly or using the 'className' parameter in the wrong way. I know I can rework it to take the string of the class name and just match it, but it seems a shame to do that. This would be so nice and DRY.
class Foo {
String name
}
class Bar {
String name
}
def foobar(field, className) {
def instance = className.findByName(jsonParams.field)
if(!instance) {
instance = new className(name: jsonParams.field)
}
return instance
}
foobar(foos, Foo)
foobar(bars, Bar)
I don't know much Java or Groovy, so I'm not sure what's possible vs impossible yet. Feel free to just tell me "No." I've tried googling and haven't found anything that really answers the question for me. A simple no would be great at this point haha.
Yes, it is possible to pass class as argument - in Groovy, classes are first class citizens (see this thread for more detail).
This construct: instance = new className(name: jsonParams.field) actually tries to create an instance of class named className, not of the class referenced by this variable. To make it compile, you need to call Class.newInstance:
class Foo {
String name
}
class Bar {
String name
}
def foobar(String name,Class clazz) {
def instance = clazz.findByName(name)
if(!instance) {
instance = clazz.newInstance(name:name)
}
return instance
}
foobar('foo', Foo)
foobar('bar', Bar)
I'm not entirely sure what you want to achieve with the findByName method, though - neither Foo nor Bar have a static method named findByName as far as I can tell.
class A {
def test() { println "parent" }
}
#Mixin(A)
class B {
def test() { println "child" }
}
new B().test() // prints "parent", but I am expecting it to print "child"
This looks like some kind of reverse inheritance.
Are mixins only to be used as a means to define new methods?
I can of course use conventional inheritance and go with extends, but the use case entails a form builder where each domain has a unique form implementation and I'd like to, in my application controller, catch form requests and do a MyUniqueDomainForm.mixin DefaultFormMethods (so I only need to define default methods when I need to, as well as not having to import my.package.app.DefaultFormMethods in each form class)
Whatever you mixin will overload whatever is already there...
In this example, at compile time B.test() overloads the inherited A.test() method
But then at runtime, A.test() is added via the mixin, which re-overloads the previously overloaded method
If it was not this way round you would not be able to alter the existing characteristics of a class using mixins
ie (this is a silly example, but I believe it gets my point across):
class AddNotMinus {
static def minus( int a, int b ) {
a + b
}
}
Integer.mixin AddNotMinus
println 10 - 10
prints 20
I'm trying to create a COM Class Library for my VBA Project and one of the limitations I've seemed to have stumbled across is using constructors on the New() subroutine. After creating the new COM class a Public Sub New() is created with the following comments
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Obviously though I want to create more subroutines with the new keyword that allow for different parameters. However, when I try to do this and implement the objects in VBA I get an error when trying to input the parameters saying "End of statement expected". If anyone has any information that would greatly be appreciated.
Thank you.
All classes exposed to COM must have a parameterless constructor - period. The reason is that when the client instantiates a class the call eventually goes into CoCreateInstance() global function (or IClassFactory::CreateInstance() which is almost the same). CoCreateInstance() (or IClassFactory::CreateInstance()) have no means for passing parameters into the constructor of the class so that class must have a paremeterless constructor - that constructor will be used to instantiate the class internally.
If you need more than a paremeterless constructor - use a factory class. Pseudocode:
// this should be made COM-exposed
interface IYourClassInterface {
};
// this should not be made COM-exposed
class CYourClass {
public:
CYourClass( parameters ) {}
};
class CYourClassFactory {
public:
CYourClassFactory() {} //<- parameterless constructor
IYouClassInterface* CreateInstance( parameters here )
{
return new CYourClass();
}
};
this way you have a factory class with a paremeterless constructor. You instantiate the factory and then call its creator method for instantiating your class.