Partial class delegation in Kotlin - multiple-inheritance

How do I partial delegate methods/fields in Kotlin?
To be specific: here I am trying to inherit class User from interface TraitA and implement field marked: Boolean in the wrapper StateA. That would clean up the User implementation, because marked is just a state field. Note that TraitA can't be a class because I want to use several such interfaces: User() : TraitA by StateA, TraitB by StateB, ..
/* does not compile (Kotlin M12) */
interface TraitA {
var marked: Boolean
fun doStaffWithMarked() // must be overridable
}
class StateA() : TraitA {
override var marked = false
}
class User() : TraitA by StateA(){
override fum doStaffWithMarked() {
//...all fancy logic here...
}
}
The alternative is to implement all in one place:
class User() : TraitA{
override var marked = false // ugly code
override fum doStaffWithMarked() {
//...
}
}
Is there a way/pattern that would solve that problem with easy and as little code as possible? Code/bytecode generation is not an option for me.
UPDATE
I was not very clear about that, but please note that doStaffWithMarked() is unique for every User.
So I may suggest a 'half-bad' solution with run-time assertions:
interface TraitA {
var marked: Boolean
/* must be overridden */
fun doStaffWithMarked() = throw UnsupportedOperationException()
}
class StateA() : TraitA {
override var marked = false
}
class User() : TraitA by StateA() {
override fum doStaffWithMarked() {
//...all fancy logic here...
}
}
The question is still open, since a really good solution would check that doStaffWithMarked() at compilation time.

Split up TraitA into two interfaces, then delegate the one and implement the other:
interface TraitA {
var marked: Boolean
}
interface TraitAPlus : TraitA {
fun isMarked(): Boolean
}
class StateA() : TraitA {
override var marked = false
}
class User() : TraitA by StateA(), TraitAPlus {
override fun isMarked(): Boolean {
return marked
}
}

Here's a version that just inherites from StateA instead of delegating but that's not very nice:
interface TraitA {
var marked: Boolean
fun isMarked(): Boolean
}
abstract class StateA() : TraitA {
override var marked = false
}
class User() : TraitA, StateA() {
override fun isMarked(): Boolean {
return marked
}
}
And here's a somewhat unusal approach where I delegate TraitA to an anonymous instance of StateA
class User() : TraitA by object : StateA() {
override fun isMarked(): Boolean {
return marked
}
} {
}
To be honest though, I'd rather rethink the design of the class hierarchy instead. In particular, you can put method implementations in interfaces (but not property values) so if isMarked() only depends on marked you could just put the implementation for it directly in TraitA. Your code then becomes:
interface TraitA {
var marked: Boolean
fun isMarked(): Boolean {
return marked
}
}
class StateA() : TraitA {
override var marked = false
}
class User() : TraitA by StateA() {
}
Edit: Separate answer: https://stackoverflow.com/a/30914383/615306

Related

How to define a private property when implementing an interface in Typescript?

I'm using TypeScript in my project and I have come across an issue.
I'm defining an interface like this:
interface IModuleMenuItem {
name: string;
}
I want to create a class that implements from this interface but I want the name to be a private property like this:
class ModuleMenuItem implements IModuleMenuItem {
private name: string;
}
I'm getting the following error:
Class ModuleMenuItem incorrectly implements interface IModuleMenuItem.
Property name is private in type ModuleMenuItem but not in type
IModuleMenuItem.
How can I define a property as private or protected when implementing an interface?
Interfaces define "public" contracts and as such it doesn't make sense to have protected or private access modifier on interfaces, which are more of a, let's call it, implementation detail. For that reason you can't do what you want with an interface.
If you want to make the property read-only to consumers, but overridable in a subclass then you can do something like this:
interface IModuleMenuItem {
getName(): string;
}
class ModuleMenuItem implements IModuleMenuItem {
private name;
public getName() {
return name;
}
protected setName(newName : string) {
name = newName;
}
}
I think in TypeScript 2.0 (not out yet) you will be able to use the readonly access modifier if you were after initialization-time readonly field - https://basarat.gitbooks.io/typescript/content/docs/types/readonly.html
interface IModuleMenuItem {
readonly name : string;
}
class ModuleMenuItem implements IModuleMenuItem {
public readonly name : string;
constructor() {
name = "name";
}
}
I think you may do it like this
interface IModuleMenuItem{
name: string
}
class ModuleMenuItem implements IModuleMenuItem {
private _name: string;
constructor() {
_name = "name";
}
get name(){
// your implementation to expose name
}
set name(value){
// your implementation to set name
}
}
In case of having private fields in class, you need to introduce setter and get methods for that field like so:
export class Model {
private _field: number;
get field(): number {
return this._field;
}
set field(value: number) {
this._field= value;
}
}
And then create the interface as usual (We can not use private modifier for interface fields) like so:
export interface IModel {
field: number;
}
Then implement it to our class like so:
export class Model implements IModel {
...
}
TypeScript will understand that this model is implemented correctly the interface as we have introduced set and get method.
The only way you can have an inner state and assign interface to that instead of class and make that state private
class A{
private state:IA = ...
}
As an addendum to Syntax's response, there is no need to include a setter. A getter method is all that is needed. This could be used, for example, for read-only variables set at initialization, though I suppose it's better to use the readonly modifier in this case.
interface IModuleMenuItem
{
name: string;
}
class ModuleMenuItem implements IModuleMenuItem{
private name$: string;
constructor(name: string)
{
this.name$ = name;
}
public get name()
{
return this.name$;
}
}
Use abstract classes instead.
Composition over inheritance.
interface AppInterface {
app: express.Application
port: string | number
}
abstract class AbstractApp implements AppInterface {
app: express.Application
port: string | number
constructor(){
this.app=express()
this.port=8080
}
protected defaultMiddlewares(): void {}
}
class App extends AbstractApp {
constructor() {
super()
}
protected defaultMiddlewares(): void {
this.app.use(express.json())
}
}

Get custom attribute on method from Castle Windsor interceptor

I am trying to access a custom attribute applied to a method within a castle interceptor, but method Attribute.GetCustomAttribute() return null.
public class MyIntecept : Castle.DynamicProxy.IInterceptor
{
public void Intercept(IInvocation invocation)
{
// myAttr is null.
var myAttr = (MyAttribute)Attribute.GetCustomAttribute(
invocation.Method, typeof(MyAttribute));
}
}
[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class MyAttribute : Attribute
{
readonly string _value;
public MyAttribute(string value)
{
this._value = value;
}
public string Value
{
get { return this._value; }
}
}
public interface IMyInterface
{
void Do();
}
public class MyClass : IMyInterface
{
[MyAttribute("MyValue")]
public void Do()
{
Console.WriteLine("Do");
}
}
How can i get 'MyAttribute'?
P.S. I'am using Castle.Core 3.3.3
Put the attribute "MyAttribute" on the method inside the interface and not inside the class

Multiple inheritence in Kotlin

Consider the following example
public class SomeActivity() : Activity(), OnClickListener {
override fun onCreate(Bundle?: savedInstanceState) {
super<Activity>.onCreate(savedInstanceState)
...
someButton.setOnClickListener(this) // How do I refer to the `OnClickListener` implementation?
}
}
How do I refer to the OnClickListener implementation in the above mentioned code snippet?
Don't forget to implement onClick(View) function and change onCreate signature. After that code will looks like below:
public class SomeActivity() : Activity(), OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super<Activity>.onCreate(savedInstanceState)
val someButton = Button(this)
someButton.setOnClickListener(this)
}
override fun onClick(v: View) {
// TODO implement
}
}
Not wanting to create an Android project, I created a mock up of your classes and there are no errors using the code mentioned in another answer:
// mocked up classes
interface Bundle {}
open class Activity {
open fun onCreate(savedInstanceState: Bundle?) {}
}
interface View {}
interface OnClickListener {
fun onClick(v: View)
}
open class Button(a: Activity) {
fun setOnClickListener(o: OnClickListener) {}
}
// the usage, showing no error:
public class SomeActivity() : Activity(), OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super<Activity>.onCreate(savedInstanceState)
val someButton = Button(this)
someButton.setOnClickListener(this) // NO ERROR
}
override fun onClick(v: View) {
// TODO implement
}
}

How to reference subclasses of static Java classes with generics in Scala

I have this Java code:
public class TestMapper extends AppEngineMapper<Key, Entity, NullWritable, NullWritable> {
public TestMapper() {
}
// [... other overriden methods ...]
#Override
public void setup(Context context) {
log.warning("Doing per-worker setup");
}
}
...which I've converted to:
class TestMapper extends AppEngineMapper[Key, Entity, NullWritable, NullWritable] {
// [... other overriden methods ...]
override def setup(context: Context) {
log.warning("Doing per-worker setup")
}
}
Now the actual problem:
Context is defined as a nested class within the org.apache.hadoop.mapreduce.Mapper class:
public static class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
//[... some other methods ...]
protected void setup(org.apache.hadoop.mapreduce.Mapper<KEYIN,VALUEIN,KEYOUT,VALUEOUT>.Context context) throws java.io.IOException, java.lang.InterruptedException { /* compiled code */ }
public class Context extends org.apache.hadoop.mapreduce.MapContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
public Context(org.apache.hadoop.conf.Configuration configuration, org.apache.hadoop.mapreduce.TaskAttemptID conf, org.apache.hadoop.mapreduce.RecordReader<KEYIN,VALUEIN> taskid, org.apache.hadoop.mapreduce.RecordWriter<KEYOUT,VALUEOUT> reader, org.apache.hadoop.mapreduce.OutputCommitter writer, org.apache.hadoop.mapreduce.StatusReporter committer, org.apache.hadoop.mapreduce.InputSplit reporter) throws java.io.IOException, java.lang.InterruptedException { /* compiled code */ }
}
So I can't tell my Scala class where/what Context actually is. If Mapper had no generics I could reference Context via
Mapper#Context
but how can I tell that Mapper has Generics?
Mapper[_,_,_,_]#Context
...didn't work.
You have to supply the exact base type for your type projection, in your case
Mapper[Key, Entity, NullWritable, NullWritable]#Context
so overriding setup would be written as
override def setup(context: Mapper[Key, Entity, NullWritable, NullWritable]#Context)
Usage can be simplified by introducing a type alias
class TestMapper extends AppEngineMapper[Key, Entity, NullWritable, NullWritable] {
type Context = Mapper[Key, Entity, NullWritable, NullWritable]#Context
override def setup(context: Context) = {
// ...
}
}
If you want to write multiple mappers you can refactor this into a trait that can be mixed into your implementation:
trait SMapper[A,B,C,D] extends Mapper[A,B,C,D] {
type Context = Mapper[A,B,C,D]#Context
}
class TestMapper extends AppEngineMapper[Key, Entity, NullWritable, NullWritable]
with SMapper[Key, Entity, NullWritable, NullWritable] {
override def setup(context: Context) = {
// ...
}
}
or for plain hadoop:
class TestMapper extends SMapper[Key, Entity, NullWritable, NullWritable] {
override def setup(context: Context) = {
// ...
}
}
The problems people have sometimes when using the accepted answer are due to a bug in Scala compiler (link).

AutoMapper Ignore an item in a collection based on a property value in the source

I'm mapping an ApplianceViewModel to a ApplianceDTO. Each Appliance has a collection of ActionViewModels which are mapped to ActionDTO. What I'd like to do is configure the mapper to ignore ActionViewModels whose IsPersisted value is False.
My ViewModel classes ...
public interface IApplianceViewModel : INotifyPropertyChanged
{
ObservableCollection<IActionViewModel> Actions { get; set; }
// other properties removed for simplicity
}
public interface IActionViewModel : INotifyPropertyChanged
{
bool IsPersisted { get; set; }
// other properties removed for simplicity
}
My DTO classes ...
public class ApplianceDTO
{
public IEnumerable<ActionDTO> Actions { get; set; }
// other properties removed for simplicity
}
public class ActionDTO
{
// properties removed for simplicity
}
I set up my mapping like this ...
Mapper.CreateMap<IApplianceViewModel, ApplianceDTO>();
Mapper.CreateMap<IActionViewModel, ActionDTO>()
var appliance = new ApplianceViewModel {
Actions = new ObservableCollection<IActionViewModel>(
new List<IActionViewModel> {
new ActionViewModel { IsPersisted = true },
new ActionViewModel { IsPersisted = false }
}};
var applianceDTO = Mapper.Map<IApplianceViewModel, ApplianceDTO>(applianceDTO);
Currently my applianceDTO will have two items in it's Actions collection, but I'd like to set up my mapping so that the ApplianceActionViewModel with the IsPersisted property set to false isn't mapped. Can I do this?
Update
Omu's comment lead me to a solution using a ValueResolver to map the collection of Actions. I'm not really happy with this solution but its the best option available.
First I created a custom ValueResolver.
public class IsPersistedCollectionResolver : ValueResolver<IApplianceViewModel, IEnumerable<ActionDTO>>
{
protected override IEnumerable<ActionDTO> ResolveCore(IApplianceViewModel source)
{
return Mapper.Map<IEnumerable<IActionViewModel>, IEnumerable<ActionDTO>>(source.Actions.Where(x => x.IsPersisted));
}
}
Then I modified my code to use it in the mapping configuration.
Mapper.CreateMap<IApplianceViewModel, ApplianceDTO>()
.ForMember(dest => dest.Actions, opt => opt.ResolveUsing<IsPersistedCollectionResolver>());
Mapper.CreateMap<IActionViewModel, ActionDTO>();
have you tried doing something like :
Mapper.map(objects.Where(o => o.IsPersisted == true))

Resources