How to make a local extension method avaiable in a function with receiver? - scope

I found an interesting thing, but I couldn't do it. Is there any way to make the local extension method available in a function with receiver.
val list = ArrayList<Any>();
fun <T> Array<T>.bind(context: MutableList<in T>, block: Array<T>.() -> Unit) {
fun Array<T>.save() {
context.addAll(this);
}
block();
}
arrayOf(1, 2, 3).bind(list) {
save(); //todo: how to bind extension in execution scope
};
I know there is an alternative way by introducing another type for the receiver, but I want to avoid it. for example:
interface Savable {
fun save();
}
fun <T> Array<T>.bind(context: MutableList<in T>, block: Savable.() -> Unit) {
val proxy = object : Savable {
override fun save() {
context += this#bind;
}
};
proxy.block();
}

There is no such feature yet, and I think in near future it won't be added either. You should just use your second version. Don't care about adding an wrapper class. The idea of avoiding introducing a wrapper class is actually, as long as you are using JVM backend, just nonsense, because by using local function you are actually adding a local class.
This is the equivalent Java code of your kotlin function, after fixing as you have suggested, with the assumption that your bind function lives in file bind.kt:
public final class BindKt {
public static <T> void bind(T[] receiver, List<? super T> context, Function1<T> block) {
class Local { // the name of local class is unimportant, as it's generated by compiler. It should looks like "package.name.BindKt$bind$X" where X is a number.
public void save(T[] receiver) {
context.addAll(receiver);
}
}
block.invoke(this); // this won't compile. Neither will yours.
}
}
As you can see save is NOT compiled to a static method, which means, if your block somehow ever called that save, an instance of Local must be fist created. So, no matter what you do, as long as you used a local function, there is basically no point in avoiding introduing a wrapper class. Your second solution is good, and just use it. It's both elegant and efficient enough.
If you really don't want add a class/object creation, move these extension functions to a package scope, and let clients import them.

Related

When providing a lambda for Runnable why I dont have to override run method?

enter image description here
val obj = Runnable {
for (i in 1..3)
{
println("$i")
Thread.sleep(500)
}
}
val r1 = Thread(obj)
r1.start()
Kotlin has a feature called the SAM(Single Abstract method) Conversion, which allows you to specify a lambda where a SAM interface is expected and the language takes care of creating the implementation for you. This makes sense because there is only one method in these interfaces (ie. Runnable), so why you should write all the boilerplate code, why not just provide the implementation of SAM as a lambda.
So in your example even though you dont override the run method, the code that you provide as lambda is actually run method's implementation. And in its complete form, it would look like this
val obj = object: Runnable{
override fun run() {
for (i in 1..3)
{
println("$i")
Thread.sleep(500)
}
}
}

Implementing Set<T>

I'm trying to wrap my head around abstract by implementing a Set data-type, like so:
abstract Set<T>(Map<T, Bool>) {
public inline function new() {
this = new Map<T, Bool>();
}
public inline function has(item:T):Bool {
return this.exists(item);
}
public inline function add(item:T):Set<T> {
this.set(item, true);
return null;
}
public inline function remove(item:T):Set<T> {
this.remove(item);
return null;
}
public inline function iterator():Iterator<T> {
return this.keys();
}
}
The compiler doesn't like this, though. It tells me Set.hx:8: characters 11-29 : Abstract Map has no #:to function that accepts IMap<util.Set.T, Bool>
I don't really understand this at all, since if I change the constructor to
public inline function new(val:Map<T, Bool>) {
this = val;
}
and then instantiate with var set = new Set(new Map());, it works.
That's pretty gross, though. I'd like the ability to instantiate Sets without exposing the underlying implementation. Ultimately, I'd prefer a constructor with the signature new(?initial:Iterable<T>). Is this possible? Am I misunderstanding something?
The problem is that currently it's impossible to instantiate Map without they key type being known (and since Set.T is a free type parameter, this doesn't work). However since the constructor is inline, T may well be known at the call site. The problem is that the compiler still tries to generate Set.new. You can avoid this by prefixing it with #:extern. Working example: https://try.haxe.org/#1D06C

In Kotlin, how do I add extension methods to another class, but only visible in a certain context?

In Kotlin, I want to add extension methods to a class, for example to class Entity. But I only want to see these extensions when Entity is within a transaction, otherwise hidden. For example, if I define these classes and extensions:
interface Entity {}
fun Entity.save() {}
fun Entity.delete() {}
class Transaction {
fun start() {}
fun commit() {}
fun rollback() {}
}
I now can accidentally call save() and delete() at any time, but I only want them available after the start() of a transaction and no longer after commit() or rollback()? Currently I can do this, which is wrong:
someEntity.save() // DO NOT WANT TO ALLOW HERE
val tx = Transaction()
tx.start()
someEntity.save() // YES, ALLOW
tx.commit()
someEntity.delete() // DO NOT WANT TO ALLOW HERE
How do I make them appear and disappear in the correct context?
Note: this question is intentionally written and answered by the author (Self-Answered Questions), so that the idiomatic answers to commonly asked Kotlin topics are present in SO. Also to clarify some really old answers written for alphas of Kotlin that are not accurate for current-day Kotlin. Other answers are also welcome, there are many styles of how to answer this!
The Basics:
In Kotlin, we tend to use lambdas passed into other classes to give them "scope" or to have behaviour that happens before and after the lambda is executed, including error handling. Therefore you first need to change the code for Transaction to provide scope. Here is a modified Transaction class:
class Transaction(withinTx: Transaction.() -> Unit) {
init {
start()
try {
// now call the user code, scoped to this transaction class
this.withinTx()
commit()
}
catch (ex: Throwable) {
rollback()
throw ex
}
}
private fun Transaction.start() { ... }
fun Entity.save(tx: Transaction) { ... }
fun Entity.delete(tx: Transaction) { ... }
fun Transaction.save(entity: Entity) { entity.save(this) }
fun Transaction.delete(entity: Entity) { entity.delete(this) }
fun Transaction.commit() { ... }
fun Transaction.rollback() { ... }
}
Here we have a transaction that when created, requires a lambda that does the processing within the transaction, if no exception is thrown it auto commits the transaction. (The constructor of the Transaction class is acting like a Higher-Order Function)
We have also moved the extension functions for Entity to be within Transaction so that these extension functions will not be seen nor callable without being in the context of this class. This includes the methods of commit() and rollback() which can only be called now from within the class itself because they are now extension functions scoped within the class.
Since the lambda being received is an extension function to Transaction it operates in the context of that class, and therefore sees the extensions. (see: Function Literals with Receiver)
This old code is now invalid, with the compiler giving us an error:
fun changePerson(person: Person) {
person.name = "Fred"
person.save() // ERROR: unresolved reference: save()
}
And now you would write the code instead to exist within a Transaction block:
fun actsInMovie(actor: Person, film: Movie) {
Transaction { // optional parenthesis omitted
if (actor.winsAwards()) {
film.addActor(actor)
save(film)
} else {
rollback()
}
}
}
The lambda being passed in is inferred to be an extension function on Transaction since it has no formal declaration.
To chain a bunch of these "actions" together within a transaction, just create a series of extension functions that can be used within a transaction, for example:
fun Transaction.actsInMovie(actor: Person, film: Movie) {
film.addActor(actor)
save(film)
}
Create more like this, and then use them in the lambda passed to the Transaction...
Transaction {
actsInMovie(harrison, starWars)
actsInMovie(carrie, starWars)
directsMovie(abrams, starWars)
rateMovie(starWars, 5)
}
Now back to the original question, we have the transaction methods and the entity methods only appearing at the correct moments in time. And as a side effect of using lambdas or anonymous functions is that we end up exploring new ideas about how our code is composed.
See the other answer for the main topic and the basics, here be deeper waters...
Related advanced topics:
We do not solve everything you might run into here. It is easy to make some extension function appear in the context of another class. But it isn't so easy to make this work for two things at the same time. For example, if I wanted the Movie method addActor() to only appear while inside a Transaction block, it is more difficult. The addActor() method cannot have two receivers at the same time. So we either have a method that receives two parameters Transaction.addActorToMovie(actor, movie) or we need another plan.
One way to do this is to use intermediary objects by which we can extend the system. Now, the following example may or may not be sensible, but it shows how to go this extra level of exposing functions only as desired. Here is the code, where we change Transaction to implement an interface Transactable so that we can now delegate to the interface whenever we want.
When we add new functionality we can create new implementations of Transactable that expose these functions and also holds temporary state. Then a simple helper function can make it easy to access these hidden new classes. All additions can be done without modifying the core original classes.
Core classes:
interface Entity {}
interface Transactable {
fun Entity.save(tx: Transactable)
fun Entity.delete(tx: Transactable)
fun Transactable.commit()
fun Transactable.rollback()
fun Transactable.save(entity: Entity) { entity.save(this) }
fun Transactable.delete(entity: Entity) { entity.save(this) }
}
class Transaction(withinTx: Transactable.() -> Unit) : Transactable {
init {
start()
try {
withinTx()
commit()
} catch (ex: Throwable) {
rollback()
throw ex
}
}
private fun start() { ... }
override fun Entity.save(tx: Transactable) { ... }
override fun Entity.delete(tx: Transactable) { ... }
override fun Transactable.commit() { ... }
override fun Transactable.rollback() { ... }
}
class Person : Entity { ... }
class Movie : Entity { ... }
Later, we decide to add:
class MovieTransactions(val movie: Movie,
tx: Transactable,
withTx: MovieTransactions.()->Unit): Transactable by tx {
init {
this.withTx()
}
fun swapActor(originalActor: Person, replacementActor: Person) {
// `this` is the transaction
// `movie` is the movie
movie.removeActor(originalActor)
movie.addActor(replacementActor)
save(movie)
}
// ...and other complex functions
}
fun Transactable.forMovie(movie: Movie, withTx: MovieTransactions.()->Unit) {
MovieTransactions(movie, this, withTx)
}
Now using the new functionality:
fun castChanges(swaps: Pair<Person, Person>, film: Movie) {
Transaction {
forMovie(film) {
swaps.forEach {
// only available here inside forMovie() lambda
swapActor(it.first, it.second)
}
}
}
}
Or this whole thing could just have been a top level extension function on Transactable if you didn't mind it being at the top level, not in a class, and cluttering up the namespace of the package.
For other examples of using intermediary classes, see:
in Klutter TypeSafe config module, an intermediary object is used to store the state of "which property" can be acted upon, so it can be passed around and also changes what other methods are available. config.value("something").asString() (code link)
in Klutter Netflix Graph module, an intermediary object is used to transition to another part of the DSL grammar connect(node).edge(relation).to(otherNode). (code link) The test cases in the same module show more uses including how even operators such as get() and invoke() are available only in context.

Using abstracts as HashMap keys in Haxe

I'm trying to create a haxe.ds.HashMap where the keys are an object I don't control. Thus, they don't implement the hashCode method and I can't change them to.
I would really like to use an abstract to accomplish this, but I'm getting some compile time errors.
Here is the code I'm playing with:
import haxe.ds.HashMap;
abstract IntArrayKey( Array<Int> ) from Array<Int> {
inline public function new( i: Array<Int> ) {
this = i;
}
public function hashCode(): Int {
// General warning: Don't copy the following line. Seriously don't.
return this.length;
}
}
class Test {
static function main() {
var hash = new HashMap<IntArrayKey, Bool>();
}
}
The compile errors are:
Test.hx:15: characters 19-51 : Constraint check failure for haxe.ds.HashMap.K
Test.hx:15: characters 19-51 : IntArrayKey should be { hashCode : Void -> Int }
But the moment I change my abstract over to a class, it compiles fine:
import haxe.ds.HashMap;
class IntArrayKey {
private var _i: Array<Int>;
inline public function new( i: Array<Int> ) {
this._i = i;
}
public function hashCode(): Int {
// General warning: Don't copy the following line. Seriously don't.
return this._i.length;
}
}
class Test {
static function main() {
var hash = new HashMap<IntArrayKey, Bool>();
}
}
It's the exact same hashCode implementation, just a different context. Is there some way to accomplish this? Or is it a language limitation?
As far as I know, abstracts currently can't satisfy type requirements like this, quoting from the code:
abstract HashMap<K:{ function hashCode():Int; }, V >(HashMapData<K,V>) {
So, I doubt you could do that in a meaningful way.
Important point would be that while abstracts can sometimes provide overhead-free abstractions which is quite useful for optimizations, the time needed to instantiate(probably hidden from sight with abstract Name(Holder) to Holder having #:from Array<Int> and #:to Array<Int>) holder for your array which will have the required method isn't that high(compared to usual runtime overheads), and unless it is a really frequent code, should be your first way to go.
However, the HashMap code itself is quite short and simple: here.
You could just copy it and make it work with your example. Maybe you could even forge a better yet generic version by using interfaces(though I'm not sure if abstracts can actually implement them).

Type parameters - get concrete type from type T : IMyInterface

Suppose I have a List<IMyInterface>...
I have three classes which implement IMyInterface: MyClass1, MyClass2, and MyClass3
I have a readonly Dictionary:
private static readonly Dictionary<Type, Type> DeclarationTypes = new Dictionary<Type, Type>
{
{ typeof(MyClass1), typeof(FunnyClass1) },
{ typeof(MyClass2), typeof(FunnyClass2) },
{ typeof(MyClass3), typeof(FunnyClass3) },
};
I have another interface, IFunnyInteface<T> where T : IMyInterface
I have a method:
public static IFunnyInterface<T> ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
IFunnyInterface<T> otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
I'm trying to call the constructor of FunnyClasses and insert as parameter my MyClass object. I don't want to know which object it is: I just want to instantiate some FunnyClass with MyClass as a parameter.
What happens when I call ConvertToFunnyClass, T is of type IMyInterface, and when I try to cast it to FunnyInterface<T>, it says I can't convert FunnyClass1, for instance, to FunnyInterface<IMyInterface>
My current workaround (not a beautiful one), is this:
public static dynamic ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
var otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
And I don't like it because the return type is dynamic, so when I access it from somewhere else, I have no idea what type it is, and I lose intellisense, and stuff. I don't know about any performance implications either.
Any clues?
Thanks in Advance!
Resolution
As I'm using C# 4.0, I could stop casting errors using covariance (output positions only), and so I changed my IFunnyInterface to
IFunnyInteface<out T> where T : IMyInterface
Thank you all for the replies.
Essentially, your problem is that you are trying to convert FunnyInterface<T> to FunnyInterface<IMyInterface>. As has been mentioned several times (one example is here, more information here), this is not valid in most circumstances. Only in .NET 4, when the generic type is an interface or delegate, and the type parameter has been explicitly declared as variant with in or out, can you perform this conversion.
Is FunnyInterface actually an interface?
thecoop answer points you exactly to why you can't do it.
A cleaner solution to the problem (besides using dynamic) would be a base non-Generics Interface:
public interface IFunnyInterfaceBase
{
}
public interface IFunnyInteface<T> : IFunnyInterfaceBase
where T : IMyInterface
{
}
And you need to move methods signature you use in that code from IFunnyInteface to IFunnyInterfaceBase.
This way you would be able to write something like this:
MyClass2 c2 = new MyClass2();
IFunnyInterfaceBase funnyInstance = c2.ConvertToFunnyClass();
The Exception you said you got in your code is not due to the extension method signature itself (the method is fine)..it is originated by the type of your lvalue (the type of the variable you use to store its return value)!
Obviously this solution applies only if you can modify IFunnyInterface source code!

Resources