I'm a C++ programmer starting with D and I'm having some trouble understanding the access qualifiers for D classes. Consider the following example:
import std.stdio;
class Foo {
private void aPrivateMethod()
{
writeln("called aPrivateMethod");
}
protected void aProtectedMethod()
{
writeln("called aProtectedMethod");
}
public void aPublicMethod()
{
this.aPrivateMethod();
this.aProtectedMethod();
}
}
void main(string[] args)
{
Foo foo = new Foo();
foo.aPublicMethod(); // OK to call it from anywhere
foo.aPrivateMethod(); // Must not be allowed to call it outside Foo
foo.aProtectedMethod(); // Should only be callable from within Foo and derived classes
}
I would expect the previous code to fail compilation, since it is calling private and protected methods of class Foo in an external function. However, this is not the case, since the example above compiles and runs without errors or warnings on DMD v2.063.2. Clearly the keywords have different meaning from those of C++.
My questions are:
1) How to make a method and/or variable private to a class so that only the class in question can access it.
2) How to make a method and/or variable protected, so that only the class in question and its derived classes can access it.
the access modifiers are module/file level (only exception is protected)
to remove access to a class put it in its own mudule:
foo.d
import std.stdio;
class Foo {
private void aPrivateMethod()
{
writeln("called aPrivateMethod");
}
protected void aProtectedMethod()
{
writeln("called aProtectedMethod");
}
public void aPublicMethod()
{
this.aPrivateMethod();
this.aProtectedMethod();
}
}
main.d
import foo;
void main(string[] args)
{
Foo foo = new Foo();
foo.aPublicMethod(); // OK to call it from anywhere
foo.aPrivateMethod(); // compile error: Must not be allowed to call it outside foo.d
foo.aProtectedMethod(); // compile error: Should only be callable from within foo.d, Foo and derived classes
}
D has a slightly different meaning to terms public private and protected than C++
Private means that only members of the enclosing class can access the member, or members and functions in the same module as the enclosing class. Private members cannot be overridden. Private module members are equivalent to static declarations in C programs.
Package extends private so that package members can be accessed from code in other modules that are in the same package. This applies to the innermost package only, if a module is in nested packages.
Protected means that only members of the enclosing class or any classes derived from that class, or members and functions in the same module as the enclosing class, can access the member. If accessing a protected instance member through a derived class member function, that member can only be accessed for the object instance which can be implicitly cast to the same type as ‘this’. Protected module members are illegal.
Public means that any code within the executable can access the member.
Related
I'm trying to achieve encapsulation by using subcomponent which is described here, but I got infinite recursion.
Here is my code:
//tried adding #ScopeA, still the same.
public class A {
#Inject
A(B b) {
}
}
#ScopeA
public class B {
#Inject
B() {
}
}
#Component(modules = AModule.class)
#Singleton
public interface AComponent {
public A a();
}
#Module(subcomponents = SComponent.class)
class AModule {
#Provides
#Singleton
A a(SComponent.Factory factory) {
return factory.component().a();
}
}
#Subcomponent
#ScopeA
interface SComponent {
#ScopeA
A a();
#Subcomponent.Factory
interface Factory {
SComponent component();
}
}
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAComponent.create().a();
}
}
After checking generated dagger code, I found this:
private final class SComponentImpl implements SComponent {
private SComponentImpl() {}
#Override
public A a() {
return DaggerAComponent.this.aProvider.get();
}
}
It seeems that SComponent are getting A from parent component, which is not what I wanted, where is the problem of my code?
Note that the example from the Subcomponents for Encapsulation page uses a qualifier annotation, #PrivateToDatabase, which is not a scoping annotation and which distinguishes the binding of Database from the binding of #PrivateToDatabase Database.
Subcomponents inherit all of the bindings from their parent components, so you currently do have A available from the parent component and also A available from the subcomponent. This is especially tricky if anything in your subcomponent needs to inject A, if it weren't marked #Singleton: Do you want the A from the parent component, or the A from the subcomponent?
Another tricky part of this situation is that you can't use qualifier annotations on classes that use #Inject constructors.
I'd recommend that you do the following:
Extract an interface from A, so then you have A and AImpl.
Keep your #Provides method that gets an A instance from the subcomponent.
Have the subcomponent expose AImpl, and (to best avoid ambiguity) only inject AImpl in the classes in your subcomponent, not A.
If you'd rather not extract an interface, you could also work around this problem by removing #Inject from A and writing a #Provides method in a module in the subcomponent that returns a qualified A, so the unqualified A goes through the top-level component and the qualified A is only available within the subcomponent.
In AEM, I have a Use class A which extends WCMUsePojo. It has one activate() method with #Override annotation where I read the property (lets say product) and assign to variable. Also, I have a getter method to read the property. Now, there is another class B which extends the Class A and has activate() method with #Override annotation. In activate method I am reading one more property.
Now, from HTL , I refer the Class B, and was trying to get "product property" (assuming that this property would be available in Class B via inheritance), But I am getting null value. But when I change the property modifier to static in Class A, then it works fine.
See the code below.
public class ClassA extends WCMUsePojo {
private String product;
#Override
public void activate() throws Exception {
product = getProperties().get(“product”, "");
}
public String getProduct() {
return product;
}
}
public class ClassB extends ClassA {
private String lotno;
#Override
public void activate() throws Exception {
lotno = getProperties().get(“lotno”, "");
}
public String getLotno() {
return lotno;
}
}
<div data-sly-use.productDetails="test.sample.ClassB"/>
${productDetails.product}
${productDetails.product} is null unless I change the product property to static in ClassA. Can somebody explain why is that so?
Just add super.activate() in your activate-method of class B.
This is Standard-Java behavior. An overridden method replaces the inherited method. The child-class has to call super.method-xyz() to re-use it. So the child class can control if the inherited method is called and when.
Additional remarks:
In case of an constructor you must call super(), because also the super-class must be initialized.
If you should use Sling-Models (what is mostly recommended), then you have the same effect. The annotation #PostConstruct is also only used for the child class. This is more confusing for everybody. That's why I don't recommend inheritance for Sling-Models in my projects. Often it is not needed.
in C++,
While granting access demoting a variable from protected to public is not allowed but it is happening.
#include<iostream>
using namespace std;
class base {
protected: int x; // x is protected
};
class derived: private base {
public: base::x; //demoting from protected to public must not happen
};
int main(){
derived d1;
d1.x=10; //protected variable x is being accessed using an object**
cout<<d1.x<<endl;
}
The int object is not what is protected, merely the name base::x
You are incorrect in your claim "protected variable x is being accessed". It is not. derived::x is a public member, which merely refers to the base::x.
The public and protected members of base are visible to derived, which is where the protected variable base::x is being accessed, by the access declaration.
I want to run the same JUnit tests for different interface implementations. I found a nice solution with the #Parameter option:
public class InterfaceTest{
MyInterface interface;
public InterfaceTest(MyInterface interface) {
this.interface = interface;
}
#Parameters
public static Collection<Object[]> getParameters()
{
return Arrays.asList(new Object[][] {
{ new GoodInterfaceImpl() },
{ new AnotherInterfaceImpl() }
});
}
}
This test would be run twice, first with the GoodInterfaceImpl then with the AnotherInterfaceImpl class. But the problem is I need for most of the testcases a new object. A simplified example:
#Test
public void isEmptyTest(){
assertTrue(interface.isEmpty());
}
#Test
public void insertTest(){
interface.insert(new Object());
assertFalse(interface.isEmpty());
}
If the isEmptyTest is run after the insertTest it fails.
Is there an option to run automatically each testcase with a new instance of an implementation?
BTW: Implementing a clear() or reset()-method for the interface is not really an options since I would not need it in productive code.
Here is another approach with the Template Method pattern:
The interface-oriented tests go into the base class:
public abstract class MyInterfaceTest {
private MyInterface myInterface;
protected abstract MyInterface makeContractSubject();
#Before
public void setUp() {
myInterface = makeContractSubject();
}
#Test
public void isEmptyTest(){
assertTrue(myInterface.isEmpty());
}
#Test
public void insertTest(){
myInterface.insert(new Object());
assertFalse(myInterface.isEmpty());
}
}
For each concrete class, define a concrete test class:
public class GoodInterfaceImplTest extends MyInterfaceTest {
#Override
protected MyInterface makeContractSubject() {
// initialize new GoodInterfaceImpl
// insert proper stubs
return ...;
}
#Test
public void additionalImplementationSpecificStuff() {
...
}
}
A slight advantage over #Parameter is that you get the name of the concrete test class reported when a test fails, so you know right away which implementation failed.
Btw, in order for this approach to work at all, the interface must be designed in a way which allows testing by the interface methods only. This implies state-based testing -- you cannot verify mocks in the base test class. If you need to verify mocks in implementation-specific tests, these tests must go into the concrete test classes.
Create a factory interface and implementations, possibly only in your test hierarchy if you don't need such a thing in production, and make getParameters() return a list of factories.
Then you can invoke the factory in a #Before annotated method to get a new instance of your actual class under test for each test method run.
Just in case somebody reaches here(like I did), looking for testing multiple implementations of the same interface in .net you could see one of the approaches that I was using in one of the projects here
Below is what we are following in short
The same test project dll is run twice using vstest.console, by setting an environment variable. Inside the test, (either in the assembly initialize or test initialize) register the appropriate implementations into a IoC container, based on the environment variable value.
In Junit 5 you could do:
#ParameterizedTest
#MethodSource("myInterfaceProvider")
void test(MyInterface myInterface) {}
static Stream<MyInterface> myInterfaceProvider() {
return Stream.of(new ImplA(), new ImplB());
}
interface MyInterface {}
static class ImplA implements MyInterface {}
static class ImplB implements MyInterface {}
what can I do to make the abstract function work in the emaillogger class?
class EmailLogger extends Zend_Log_Writer_Abstract
and I want to use the function _write
protected function _write($event)
{
$this->_events[] = $this->_formatter->format($event);
}
then I got this error
Class EmailLogger contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Zend_Log_FactoryInterface::factory)
I am not really sure what to do here
I try'd to use implements Zend_Log_FactoryInterface, but it diddn't work
thanks, Richard
Zend_Log_Writer_Abstract implements Zend_Log_FactoryInterface which has the following code:
static public function factory($config);
This forces the Zend_Log_Writer_Abstract and any child classes to also have a factory method. To satisfy this requirement, you could put in a wrapper method which calls the parent method:
class EmailLogger extends Zend_Log_Writer_Abstract
{
// Add this method in conjunction to what you already have in your class
public static function factory($config)
{
parent::factory($config);
}
}