Translate

Monday, 9 April 2018

Explicit interface method - C#

Note: Putting the angular brackets < and > in a blogger post is more difficult than generics !

Continuing with generics, one of  my favorite language features, but this time in C#, the more dynamic of generic implementation in all programming languages, the premise, again from an example from Stackoverflow, is that there are two interfaces, IEquipment and 
IEquipmentDataProvider, with the latter providing for a generic method, GetEquipment, that returns a type of IEquipment.   

The question being on Stackoverflow ie., whether 
IEquipment
GetEquipment<E>(string Path) where E : IEquipment, new();

is correct or should there be an alternate way of working on the intent? 

An intent is what an interface is about and so when a constraint is declared on a generic method, or a normal method, the expansion of the constraint at implementation is what reveals the design of the intent. In this instance, it is a constraint that says all implementing classes must be of type 
IEquipment (
where E : IEquipment) and should have a parameterless constructor - , new().

So, what does it mean as a design when the interface IEquipmentDataProvider declares it like so,

public interface IEquipmentDataProvider
{
  IEquipment GetEquipment<E>(string Path) where E : IEquipment, new(); 
} 


public interface IEquipment{

}
public interface IEquipmentDataProvider:IEquipment
{
  IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();
}
public class Equipment:IEquipment{
public Equipment(){

}
public IEquipment GetEquipment<E>(string Path){
Equipment eqp=new Equipment();
IEquipment ieq=(IEquipment) eqp;
return ieq;
}

public class EquipmentDataProvider:IEquipmentDataProvider{
public EquipmentDataProvider(){

}
public IEquipment GetEquipment<E>(string Path){
EquipmentDataProvider eqp=new EquipmentDataProvider();
IEquipmentDataProvider iedp = (IEquipmentDataProvider) eqp;
return iedp;
}
public static void Main(){
IEquipmentDataProvider da=(IEquipmentDataProvider)new EquipmentDataProvider();
IEquipment eq = (IEquipment)da.GetEquipment<Equipment>("somepath");
System.Console.WriteLine(eq);
}
}

For the above code, the compiler rejects the interface implementation because E cannot be expanded into a type conforming to the constraints because a type of IEquipment does not exist with a parameterless constructor and a corresponding GetEquipment method. ie., had the IEquipment interface declared the GetEquipment method in it instead of the IEquipmentDataProvider, the error would have been for IEquipment because the implementing class, Equipment, too, has not implemented the method as an interface method!!


It can be quite vexing if one does not know C# well, which has a feature where a method can be explicitly defined so that the interface implementation conforms to what the compiler expects.

This means that you simply qualify the method with the interface name prefixed, like so:

public IEquipment IEquipmentDataProvider.GetEquipment(string Path){

}

But since it is an explicit method definition, the compiler throws an error that the public modifier cannot be applied on it!


Because it is typed specifically as an interface method! Cool, isn't it!?

Modify the signature of the method and the complete code is as below:

public interface IEquipment{

}

public interface IEquipmentDataProvider:IEquipment
{
  IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();
}
public class Equipment:IEquipment{
public Equipment(){}
public IEquipment GetEquipment<E>(string Path){
Equipment eqp=new Equipment();
IEquipment ieq=(IEquipment) eqp;
return ieq;

}
public class EquipmentDataProvider:IEquipmentDataProvider{
public EquipmentDataProvider(){}
IEquipment IEquipmentDataProvider.GetEquipment<E>(string Path){
EquipmentDataProvider eqp=new EquipmentDataProvider();
IEquipmentDataProvider iedp = (IEquipmentDataProvider) eqp;
return iedp;
}
public static void Main(){
IEquipmentDataProvider da=(IEquipmentDataProvider)new EquipmentDataProvider();
IEquipment eq = (IEquipment)da.GetEquipment<Equipment>("somepath");
System.Console.WriteLine(eq);
}
}

and, the output, even though the method returns an IEquipment type is actually an EquipmentDataProvider type!!



Happy C#-ing and generic interfacing, whatever may be the constraints!

Thursday, 5 April 2018

Generic type constraints in Typescript

Platform: nodejs
npm install typescript, ts-node, mocha, babel

Generics from the C# days of 2005 onwards is a much-underused technique to implement type safety and security.

Here is a look at the fascinating feature using a mocha test and a couple of es6 classes and interface. Needless to say, this post, too, is inspired by a question from SO.

First, the premise.

An interface - interface DiscreteLinearOrder - with a generic type constraint - - declares two methods - next and lessThanOne - which are implemented in all deriving classes.

Another class that implements this interface imposes its own constraint in this form -

class DLOinterval<V, U extends DiscreteLinearOrder<any>>
implements DiscreteLinearOrder -

for the simple requirement that any consuming object is not typed as

const aaa = new abc.DLOinterval<number, string
>

or any other type but DiscreteLinearOrder interface type.

Like so,

const aaa = new abc.DLOinterval<number, abc.DLOnumber>

where abc.DLOnumber is another class implementing the DiscreteLinearOrder interface.




The interesting aspect that I originally chose this scenario was to explore the type inference happening at compile time in generics ie.,



The red squiggly line, in the above screenshot, indicates an error that since T is already the first parameter, typing another parameter with the same constraint causes the compiler to build an inference tree from the same parameter list, which had it not been a generic type would have simply been explained as a variable name already used but since T is not a variable but a type, it demonstrates that its duplicate usage causes a constraint to become almost like an infinite constraint as they both refer to each other!

Below is the code to be compiled with 

  1. tsc   
  2. mocha --compilers <path to ts-node\register> testfilename.ts
// testname.ts
import {expect} from 'chai'
import * as abc from './discretelo'
import 'mocha'
describe('a test', () => { 
it('interface', function(){
const aaa = new abc.DLOinterval<number, abc.DLOnumber>
(new abc.DLOnumber(3),new abc.DLOnumber(5),null,2)
    expect(aaa.next()).to.equal(3)
})
});
// discretelo.ts

interface DiscreteLinearOrder<T> {
    next:()=>T;
    lessThan(y:T):Boolean;
}
export class DLOnumber implements DiscreteLinearOrder<number> {
    private value: number;
    constructor(x: number) { this.value = x; }
    next = () => { return(this.value + 1); };
    lessThan = (y: number) => { return(this.value < y); };
    getValue = () => { return(this.value.toString()); }
}
export class DLOinterval<V, U extends DiscreteLinearOrder<any>>
implements DiscreteLinearOrder<number>{
    private start: U;
    private end: U;
    private data: any;
    private value: number;
    constructor(s: U, e: U, d: any,v:number) {
        this.value=v
        this.start = s;
        this.end   = e;
        this.data  = d;
    }
        next = () => { return(this.value + 2); };
        lessThan = (y: number) => { return(this.value < y); };
}



Make the test pass by changing the expected value!

Happy generic testing typsecript!

Friday, 30 March 2018

Testing a typescript class with mocha

Platform: nodejs
Install typescript, mocha for nodejs and the associated typings for mocha. 

The story starts with coming across some mocha problem caused by the usage of the implements keyword in Typescript in one of the forums for techies.

As ever, I picked it up and decided to write a mocha test to see what was the problem.

The test result revelations were as interesting as the Cambridge analytica fiasco and the subsequent handling of it in Singapore!

Some premise before I take you through to the bumper details!
.
An interface, in Typescript, serves as the blueprint much like in the other languages but it serves an additional purpose of defining how classes would implement them.

For instance, for a class that accepts a locale and a local time value, if the interface types the two parameters as a string and a number, scoped public respectively, then the class is forced to apply the same constraints. Even implementing the public property as private is not allowed.


// IClockTime.ts

export default interface IClockTime {
    new (time: number): IClock;
}

// IClock.ts

export default interface IClock {
    currentTime: number;
    locale: string;  
}

// Clock.ts

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class Clock implements IClock {
    constructor(public currentTime:string) { 
        this.currentTime=currentTime
        }        
    public tellTime(t:IClockTime){
            return new t(this.currentTime);
        }
}

// AnotherClock.ts

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class AnotherClock implements IClock {
    constructor (public currentTime: string, count: number) {
        this.currentTime=currentTime
        this.count=count
    }
    public tellTime(t:IClockTime){
            return new t(this.currentTime);
        }
}

// interfacestest.ts

import ClockTime from './IClockTime'
import AnotherClock from './anotherclock'
import Clock from './clock';
import {expect} from 'chai'
import 'mocha'
describe('an interface test', () => {  
it('to check time', () => {
var cc: ClockTime=Clock;
var cc1:ClockTime=AnotherClock
var ci = new cc(9.15,"GMT",12);
    expect(ci.tellTime(Clock)).to.equal('9:15');
  });
});


The tsc compiler is shrewd! It has noticed that the AnotherClock class has gone ahead and implemented some member of its own and not followed the blueprint provided by the IClock interface. This is much in the comfort zone of C# programmers.

It also correctly identifies what all AnotherClock has incorrectly implemented.

Modify the anotherClock class like so:

// AnotherClock.ts

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class AnotherClock implements IClock {
   private _currentTime:number;
    private _locale:string;
    public get currentTime():number{
        return this._currentTime
    }
    public set currentTime(newtime:number){
        this._currentTime=newtime
    }
    private get locale():string{
        return this._locale
    }    
    private set locale(newlocale:string){
        this._locale=newlocale
    }
    constructor (currentTime: number, locale: string) {
        this.currentTime=currentTime
        this._locale=locale
    }
    public tellTime(){
            return this.currentTime;
        }
}

And you get errors from tsc that the property locale is not in sync with how the interface published it!


I will scope this to an example of a test of the class behavior and test whether the Clock returns the time expected of it, given the locale.

The Clock class, too, attempts its own tricks by supplying a string to a parameter of type IClockTime when it types the parameter of the checkLocale() method as a IClockTime rather than as a string. Change the parameter from t:IClockTime to t:string.

Modify the Clock class like so:

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class Clock implements IClock {
    private _currentTime:number;
    private _locale:string;
    public get currentTime():number{
        return this._currentTime
    }
    public set currentTime(newtime:number){
        this._currentTime=newtime
    }
    constructor(currentTime:number, public locale:string) { 
        this.currentTime=currentTime
        this._locale=locale
        }        
    private checkLocaleTime(t:string){
        if (this._locale==="GMT")
        this.currentTime=this.currentTime-5.00
        
    }
    public tellTime(){
            this.checkLocaleTime(this.locale)
            console.log(this.currentTime)
            return this.currentTime.toString();
        }
}


Modify the test like so:

// interfacetest.ts

import ClockTime from './IClockTime'
import anotherClock from './anotherclock'
import Clock from './clock';
import IClock from './IClock'
import {expect} from 'chai'
import 'mocha'
describe('an interface test', () => {  
it('to check time', () => {
let cc= new Clock(9.15,"GMT");
    expect(cc.tellTime()).to.equal('9:15');
  });
});



Modify the expectation to match the GMT (approx.!) time and make the test pass!

Happy typescripting interfaces and classes for ES5!

Monday, 26 March 2018

The unhandled Promise rejection state and the others

Promises can be pleasant as well as vexing. In Javascript/node.js context, that is.

A promise can have three states: pending, fulfilled (resolved) or rejected.

Using a ES6 class, I managed to simplify the test that would demonstrate the three states and an additional, 'falsey' state!

First, the falsey state, as it can be confusing as an error message.


This message is caused when a Promise returns empty and is not handled in the test (mocha) either!

// mochatest.js

const assert=require('chai').assert
const asyncpromise=require('./asyncpromiserejection.js')
describe("asyncTests", () => {
it("handles Promise rejection",async ()=>{
    var t=new asyncpromise(false)
    await t.PTest().then(function () {
     console.log("Promise Resolved");
})
})        
});


// asyncpromiserejection.js

class asyncpromise{ 
    constructor(s){
        this.s=s
    }
PTest(){    
    var somevar = false;
    somevar=this.s;
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
          // throw new Error("Promise rejcted")
            reject();
    });
}
}
module.exports=asyncpromise

As the else part in the code above does not do anything, it simply causes a promise rejection but since it is not handled in the test - there is no catch to handle the broken promise chain - it causes the message of a falsey.

Now, modify the test like so, by adding the catch block to handle the promise rejection state:

const assert=require('chai').assert
const asyncpromise=require('./asyncpromiserejection.js')
describe("asyncTests", () => {
it("handles Promise rejection",async ()=>{
    var t=new asyncpromise(false)
    await t.PTest().then(function () {
     console.log("Promise Resolved");
}).catch((error)=>{
    console.log("Promise rejected")
   // assert.equal(error.message,"Promise rejected")
})
})        
});




You can test for custom error messages returned by the rejected promise, like so:


class asyncpromise{ 
    constructor(s){
        this.s=s
    }
PTest(){    
    var somevar = false;
    somevar=this.s;
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
           throw new Error("Promise rejcted")
           // reject();
    });
}
}
module.exports=asyncpromise


And the test, to include the assertion:

const assert=require('chai').assert
const asyncpromise=require('./asyncpromiserejection.js')
describe("asyncTests", () => {
it("handles Promise rejection",async ()=>{
    var t=new asyncpromise(false)
    await t.PTest().then(function () {
     console.log("Promise Resolved");
}).catch((error)=>{
   // console.log("Promise rejected")
    assert.equal(error.message,"Promise rejected")
})
})        
});



Make the test pass by simply correcting the typo in the error message!