@dalewking The idea is to have the ability to write library code like:
inline class Index_(val pos:Int) {
inline operator fun plus(value:Int):Index_ = Index_{val+value}
}
inline class ParamHelper_(val statement: PreparedStatement) {
inline operator fun Int.unaryPlus():Index_ { statement.setInt(1, this); return Index_(2) }
inline operator fun Long.unaryPlus():Index_ { statement.setLong(1, this); return Index_(2) }
inline operator fun String.unaryPlus():Index_ { statement.setString(1, this); return Index_(2) }
inline operator fun Boolean.unaryPlus():Index_ { statement.setBoolean(1, this); return Index_(2) }
inline operator fun Byte.unaryPlus():Index_ { statement.setByte(1, this); return Index_(2) }
inline operator fun Short.unaryPlus():Index_ { statement.setShort(1, this); return Index_(2) }
inline operator fun Index_.plus(value:Int):Int { statement.setInt(this.pos, value); return this+1 }
inline operator fun Index_.plus(value:Long):Int { statement.setLong(this.pos, value); return this +1 }
inline operator fun Index_.plus(value:String):Int { statement.setString(this.pos, value); return this +1 }
inline operator fun Index_.plus(value:Boolean):Int { statement.setBoolean(this.pos, value); return this +1 }
inline operator fun Index_.plus(value:Byte):Int { statement.setByte(this.pos, value); return this +1 }
inline operator fun Index_.plus(value:Short):Int { statement.setShort(this.pos, value); return this +1 }
}
inline fun <R> PreparedStatement.params(block:ParamHelper_.() -> R) =ParamHelper_(this).block()
This library code would then be used the following way:
val s : PreparedStatement = /* some java.sql.PreparedStatement out of the context */
s.params { +"Param 1" + IntParam2 + booleanParam3 }
That would be compiled to the same bytecode as:
val s : PreparedStatement = /* some java.sql.PreparedStatement out of the context */
s.setString(1, "Param 1")
s.setString(2, IntParam2)
s.setString(3, booleanParam3)
The way it would work is that the inline class would basically introduce a symbol/name scope, but otherwise would be backed by the fields. These fields would actually live as local variables on the caller stack (preferably not duplicated if they already were locals, but new variables if they were not (field references, expressions, etc.).
So for example for the Index_
class, this class would at bytecode level not exist, and just be a regular int (primitive preferred), but the compiler would only allow the specified operations (in this case operator Plus) to be invoked and no others.
The optimizer should also be smart enough to know that the values are known at compile time, and propagate the values instead of using fields/operations.
Note that the code would (without inline class) work, but be quite inefficient with too many temporaries. The temporaries would also very likely not be elided by the jvm. While it may be possible to achieve the desired effect through lambda tricks with higher order functions,that would still have the issue of not being as elegant (the operators would be introduced as parameters on the lambda), and make name scoping quite problematic.
I am however more concerned on the elegance of using this functionality that the elegance of the library code that provides it (clear, concise, elegant, simple are of course of value there too).
Btw. this (small-ish) change would also give “free” multiple return values from inline functions.