A generic function and class constrained by a type
The complete source of generics_event_handlers.ek9, compiled by the EK9 compiler. Shown on generics.html.
#!ek9 defines module site.generics.eventHandlers defines function //Generic function - now open so can be extended once parameterized. eventHandler of type T constrain by Shape as open -> shape as T require shape? //Now it is possible access the 'description' method if needs be. require shape.description()? defines class Text mainValue as String? default private Text() as pure Text() as pure -> content as String mainValue:=? String(content) mainValue() as pure <- rtn as String: String(mainValue) default operator ? Shape as abstract shapeInfo as String? default private Shape() as pure Shape() as pure -> info as String shapeInfo:=? String(info) description() as pure <- rtn as String: String(shapeInfo) override operator ? as pure <- rtn as Boolean: shapeInfo? Circle is Shape private Circle() as pure -> info as String //Must chain to an accessible initialising super - Shape's no-arg default is private (E07176). super(info) Circle() as pure super("Circle") roundness() as pure <- rtn as Float: 0.0 Square is Shape private Square() as pure -> info as String //Must chain to an accessible initialising super - Shape's no-arg default is private (E07176). super(info) Square() as pure super("Square") defines program ExampleDriver1() stdout <- Stdout() stdout.println("Driver for generic event handler") eventProcessor <- ShapeEventProcessor() //This is not allowed because eventHandler is constrained to Shape //textHandler <- (eventProcessor) is eventHandler of Text //Setup some event handlers and an example //Process through 'Shape' shapeHandler <- (eventProcessor) is eventHandler of Shape as function eventProcessor.processShapeEvent(shape) //Now type safe via generics and direct call to specific method circleHandler <- (eventProcessor) is eventHandler of Circle as function //Note strict typing means method 'roundness' is accessible. Stdout().println("Roundness " + $shape.roundness()) eventProcessor.processCircleEvent(shape) //While handler is specific to Square can still call via processShapeEvent squareHandler <- (eventProcessor) is eventHandler of Square as function eventProcessor.processShapeEvent(shape) //make some calls on the event handlers shapeHandler(Circle()) shapeHandler(Square()) circleHandler(Circle()) squareHandler(Square()) //Will not compile - which is correct! //circleHandler(Square()) //squareHandler(Circle()) defines class //non-generic processor ShapeEventProcessor stdout as Stdout: Stdout() processShapeEvent() -> shape as Shape require shape? stdout.println(`Processed shape [${shape.description()}]`) processCircleEvent() -> circle as Circle require circle? stdout.println(`Processed circle [${circle.description()} roundness ${$circle.roundness()}]`) default operator ? defines program ExampleDriver2() stdout <- Stdout() stdout.println("Driver for generic event handler and generic processor") eventProcessor as GenericShapeEventProcessor of Shape: GenericShapeEventProcessor() shapeHandler <- (eventProcessor) is eventHandler of Shape as function eventProcessor.processShapeEvent(shape) //make some calls on the event handler shapeHandler(Circle()) shapeHandler(Square()) defines class GenericShapeEventProcessor of type T constrain by Shape stdout as Stdout: Stdout() default GenericShapeEventProcessor() GenericShapeEventProcessor() -> shape as T require shape? processShapeEvent() -> shape as T require shape? stdout.println(`Processed shape [${shape.description()}]`) default operator ?
Download generics_event_handlers.ek9
Output
ExampleDriver1
Driver for generic event handler Processed shape [Circle] Processed shape [Square] Roundness 0.0 Processed circle [Circle roundness 0.0] Processed shape [Square]
ExampleDriver2
Driver for generic event handler and generic processor Processed shape [Circle] Processed shape [Square]