Visual Basic With Equivalent in Kotlin - kotlin

In Visual Basic we can use With Expression like this:
With theCustomer
.Name = "Coho Vineyard"
.URL = "http://www.cohovineyard.com/"
.City = "Redmond"
End With
I'm looking for something like this. Is it possible in Kotlin?

Kotlin provides multiple, so called, scope functions. Some of them make use of a function literal with receiver, which make it possible to write similar code as provided by you in Visual Basic. Both, with and apply are suitable for this case. It's interesting to note that with returns some arbitrary result R while apply always returns the concrete receiver on which the function has been invoked.
For your example, let's consider both functions:
with
Using with, we can write the code as follows:
val customer = Customer()
with(customer) {
name = "Coho Vineyard"
url = "http://www.cohovineyard.com/"
city = "Redmond"
}
The last expression of the lambda passed to with here is an assignment, which, in Kotlin, returns Unit. You could assign the result of the with call to some new variable which would then be of type Unit. This is not useful and the whole approach is not very idiomatic since we have to separate the declaration from the actual initialization of customer.
apply
With apply on the other hand, we can combine declaration and initialization as it returns its receiver by default:
val customer = Customer().apply {
name = "Coho Vineyard"
url = "http://www.cohovineyard.com/"
city = "Redmond"
}
As you can see, whenever you want to initialize some object, prefer apply (extension function defined on all types). Here's another thread on the differences between with and apply.

You can use with function from the Kotlin Standard library, e.g.:
with(theCustomer) {
name = "Coho Vineyard"
url = "http://www.cohovineyard.com/"
city = "Redmond"
}
with() returns some result. It makes code cleaner.
Also you can use apply extension function:
theCustomer.apply {
name = "Coho Vineyard"
url = "http://www.cohovineyard.com/"
city = "Redmond"
}
apply - declared on Any class, it could be invoked on instances of all types, it makes code more readable. Use when need to utilize an instance of the object (modify properties), express the chain of calls.
It differs from with() in that it returns Receiver.

Something like this?
with(theCustomer) {
Name = "Coho Vineyard"
URL = "http://www.cohovineyard.com/"
City = "Redmond"
}
But with requires non-nullable parameter. I suggest using let or apply instead.
theCustomer?.apply{
Name = "Coho Vineyard"
URL = "http://www.cohovineyard.com/"
City = "Redmond"
}
or
theCustomer?.let{ customer ->
customer.Name = "Coho Vineyard"
customer.URL = "http://www.cohovineyard.com/"
customer.City = "Redmond"
}

Related

How does Kotlin's data class copy idiom look for nullable types?

I have some code which looks like this, where param is of a data class type:
val options = if (param.language == null) {
param.copy(language = default())
} else {
param
}
Now, however, the language object has been moved into a hierarchy of nullable objects, so the check must look like this:
if (param.subObj?.nextObj?.language == null) { ... }
How do I use the copy idiom in this case?
One way to do this is:
val newParam = when {
param.subObj == null -> param.copy(subObj = SubObj(nextObj = NextObj(language = Language())))
param.subObj.nextObj == null -> param.copy(subObj = param.subObj.copy(nextObj = NextObj(language = Language())))
param.subObj.nextObj.language == null -> param.copy(subObj = param.subObj.copy(nextObj = param.subObj.nextObj.copy(language = Language())))
else -> param
}
I agree that this doesn't look very clean but this seems to be the only way to me, because at each step you need to check if the current property is null or not. If it is null, you need to use the default instance otherwise you need to make a copy.
Could you do something like this?
// you could create a DefaultCopyable interface if you like
data class SubObj(val prop1: Double? = null, val nextObj: NextObj? = null) {
fun copyWithDefaults() =
copy(prop1 = prop1 ?: 1.0, nextObj = nextObj?.copyWithDefaults() ?: NextObj())
}
data class NextObj(val name: String? = null) {
fun copyWithDefaults() = copy(name = name ?: "Hi")
}
I think you need a special function because you're not using the standard copy functionality exactly, you need some custom logic to define defaults for each class. But by putting that function in each of your classes, they all know how to copy themselves, and each copy function that works with other types can just call their default-copy functions.
The problem there though is:
fun main() {
val thing = SubObj(3.0)
val newThing = thing.copyWithDefaults()
println("$thing\n$newThing")
}
> SubObj(prop1=3.0, nextObj=null)
> SubObj(prop1=3.0, nextObj=NextObj(name=null))
Because nextObj was null in SubObj, it has to create one instead of copying it. But the real default value for name is null - it doesn't know how to instantiate one with the other defaults, that's an internal detail of NextObj. You could always call NextObj().copyWithDefaults() but that starts to look like a code smell to me - why isn't the default value for the parameter the actual default value you want? (There are probably good reasons, but it might mean there's a better way to architect what you're up to)

Kotlin: class instance variable value-parameter error

First post - New to Kotlin so beginner-learner. Please be gentle if my terminology is not quite up to scratch yet!
I'm attempting to call a parameter that i've declared in a secondary constructor within my main function variable but it doesnt format like the primary constructor variables and doesn't let me initialise a value that can then be called like the others.
Problem line: (it's the 'age =' bit)
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
full syntax below:
fun main() {
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
var phoneOne = MobilePhone("Samsung", "Galaxy", "S20",)
println("What is your hobby?: ")
phoneOne.hobby = readLine().toString()
phoneOne.stateHobby()
phoneTwo.hobby = "Plumbing"
phoneTwo.stateHobby()
phoneTwo.age = 32
println("PhoneTwo is $phoneTwo.age years old")
}
class MobilePhone(osName: String, brand: String, model: String) {
// member variables - Properties - variables within a class
var age : Int? = null
var hobby : String = "Watch Netflix"
// Initializer block
init {
println("A new mobile phone was created called $osName which is " +
"brand $brand and it's model is $model")
}
// member secondary constructor
constructor(osName: String, brand: String, model: String, age: Int):
this(osName,brand,model){
this.age = age
}
// Member function - functions within a class
fun stateHobby() {
println("Your hobby is $hobby")
}
This is about the syntax of calling a method/constructor in Kotlin, not about secondary constructors as such (which are called in exactly the same way as others).
First, let's review the syntax for calling a method (or constructor). You can just list the arguments alone (just as you do in Java, C, or many other languages), e.g.:
MobilePhone("Apple", "iphone", "X", 5)
However, Kotlin also allows you to specify the names of the parameters they're being passed to, e.g.:
MobilePhone(osName = "Apple", brand = "iphone", model = "X", age = 5)
That's more long-winded, but you may find it easier to read and safer (especially if there are multiple parameters with the same type). It also lets you put the arguments in any order, e.g.:
MobilePhone(model = "X", osName = "Apple", age = 5, brand = "iphone")
You can even mix and match the forms, as long as the unnamed arguments come first, e.g.:
MobilePhone("Apple", "iphone", age = 5, model = "X")
(This feature is only mildly useful on its own, but is very handy for a related feature: the ability to specify default values for some or all of the parameters. See that link for more.)
Hopefully this illustrates why the problem line doesn't make sense:
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
That looks like you want to call the secondary constructor, passing the values "Apple", "iphone", and "X" to the first three parameters, and then naming another parameter but without passing it a value. This is of course a syntax error.
If you have a value to pass for the age, then just pass it, either with the parameter name:
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = 5)
or without:
var phoneTwo = MobilePhone("Apple", "iphone", "X", 5)
Or if you don't have a value, then simply call the primary constructor instead:
var phoneTwo = MobilePhone("Apple", "iphone", "X")
Incidentally, this means that your class doesn't actually need a secondary constructor at all. You could simply include the optional parameter in the primary constructor, with a default value:
class MobilePhone(osName: String, brand: String, model: String, var age: Int? = null) {
Then callers can either specify the age param, or omit it (and get the null default value).
In fact, features such as multiple constructors, method overloading, and builder classes tend to be used less in Kotlin than in some other languages, because default parameters cover their main use cases.
I'm not sure what you're trying to do exactly, but hopefully this covers it! This:
var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
is trying to call your secondary constructor, and you're using a named argument for one of the parameters (age) but you're not actually passing a value for it. If you do, it'll compile
MobilePhone("Apple", "iphone", "X", age = 3)
You don't actually need to name the argument there - if you just pass an Int as the 4th parameter, it'll match your secondary constructor's signature (number of parameters, correct types for each, in the same order), so the compiler will know that's what you're calling. If you omit it, it'll match the primary constructor. You can still keep the name there for readability, if you like.
But you can actually duplicate the functionality you have there with a default parameter, which is where you supply a value to use if the call doesn't specify one:
class MobilePhone(osName: String, brand: String, model: String, val age: Int? = null) {
// member variables - Properties - variables within a class
var hobby : String = "Watch Netflix"
// Initializer block
init {
println("A new mobile phone was created called $osName which is " +
"brand $brand and it's model is $model")
}
So now, age is a parameter on the primary constructor - if you don't supply it (just calling with the first 3 items, which are required because they don't have defaults) then it defaults to null.
By making that parameter a val (or a var if you like) it becomes a class property you can reference later, instead of only being accessible during construction. So you can remove the var age property inside the class, because this is basically the same thing (and they'll clash anyway)
And now that you have a primary constructor you can call with or without the age parameter, there's no need for the secondary one anymore! This is where named parameters really come in useful - if you had defaults for each of those params, you could just supply the specific ones you're interested in, by using their names
oh also, "PhoneTwo is $phoneTwo.age years old" won't work - if you're just referencing an object, you can do $phoneTwo, but anything more complicated (like accessing one of its properties, or any method calls or more complex expressions) have to be wrapped in ${}
println("PhoneTwo is ${phoneTwo.age} years old")
println("PhoneTwo is ${phoneTwo.age * 365} days old")

Kotlin - Is there a way to pass property values to another object with properties of the same name?

Is there a way to pass property values to another object with properties of the same name to avoid having "repeated" code?
For example, avoid having where CepReceiptsInfo is different class than value but they share some properties name and type :
val cepReceiptsInfo = CepRecepitsInfo()
cepReceiptsInfo.operationTimestamp = value.operationTimestamp
cepReceiptsInfo.sentDate = value.sentDate
cepReceiptsInfo.sentTime = value.sentTime
cepReceiptsInfo.concept = value.concept
cepReceiptsInfo.referenceNumber = value.referenceNumber
cepReceiptsInfo.amount = value.amount
cepReceiptsInfo.trackingKey = value.trackingKey
cepReceiptsInfo.bankTarget = value.bankTarget
cepReceiptsInfo.bankSource = value.bankSource
cepReceiptsInfo.sourceClienteName = value.sourceClienteName
cepReceiptsInfo.beneficiaryName = value.beneficiaryName
cepReceiptsInfo.accountNumberTarget = value.accountNumberTarget
cepReceiptsInfo.term = value.term
cepReceiptsInfo.authorizationNumber = value.authorizationNumber
cepReceiptsInfo.linkCep = value.linkCep
cepReceiptsInfo.status = value.status
cepReceiptsInfo.bankSourceRefund = value.bankSourceRefund
cepReceiptsInfo.causeRefund = value.causeRefund
cepReceiptsInfo.accountTargetRefund = value.accountTargetRefund
cepReceiptsInfo.currency = value.currency
cepReceiptsInfo.accountNumberSource = value.accountNumberSource
cepReceiptsInfo.accountTypeSource = value.accountTypeSource
cepReceiptsInfo.accountTypeTarget = value.accountTypeTarget
cepReceiptsInfo.indicatorRefund = value.indicatorRefund
cepReceiptsInfo.amountIntRefund = value.amountIntRefund
cepReceiptsInfo.operationRefundTimestamp = value.operationRefundTimestamp
cepReceiptsInfo.dateMovement = value.dateMovement
cepReceiptsInfo.timeMovement = value.timeMovement
cepReceiptsInfo.dateRefund = value.dateRefund
cepReceiptsInfo.timeRefund = value.timeRefund
to something like f.e.:
val cepReceiptsInfo = CepReceintsInfo()
cepReceiptsInfo.assignFrom(value)
both Classes are data classes.
I don't know of a way without reflection.
fun Any.assignFrom(other: Any) {
val thisProperties = this::class.memberProperties
.filterIsInstance<KMutableProperty<*>>()
.map { it.name to it }
.toMap()
for (property in other::class.memberProperties){
thisProperties[property.name]?.setter?.call(this, property.getter.call(other))
}
}
As Tenfour04 says, the language doesn't provide a direct way of doing this, so you're limited to using extra compile-time tools, or Reflection at runtime.
Since this is a fairly common problem, there's a Java library called ModelMapper which does this for you; and as with just about all Java libraries, you can use it in Kotlin too.
(I've used it on occasion.  It can avoid lots of boilerplate.  Though I didn't find it as refactoring-safe as the front page claims…  It also ‘hides’ references to fields in a way that IDEs won't track.  So it's not a perfect solution.)

How should I define these complex initializer for a property

Although I checked all tests in the kotlinpoet code, but I didn't find a proper way to implement below target codes, or I am not sure whether I used the best approach to do that. If anyone can provide some comments about this, that would be highly appreciate.
These properties are defined in the function of a class
Target Code 1
val outputState = StateType1(iouValue, ourIdentity, otherParty)
I used below codes to generate above code
.addCode(CodeBlock.of("%L",
PropertySpec.builder("outputState", ClassName("","StateType1"))
.initializer(CodeBlock.of("%T(%L, %L, %L)", ClassName("","StateType1"), "iouValue", "ourIdentity", "otherParty"))
.build()))
But question would be this outputState might be from different types, for example, StateType1 has 3 parameters, but StateTyp2 might only has 1 parameter, how should I dynamically define my kotlinpoet code to generate correct target code.
Target Code 2
val txBuilder = TransactionBuilder(notary = notary)
.addOutputState(outputState, TEMPLATE_CONTRACT_ID)
I didn't find a reference test case which has this scenario, after property's initializer then invoke it's function directly.
Use CodeBlock.Builder for the first example, it gives you more flexibility in constructing CodeBlocks:
fun createConstructorCall(type: TypeName, vararg args: String): CodeBlock {
val argsCode = args
.map { CodeBlock.of("%L", it) }
.joinToCode(separator = ", ", prefix = "(", suffix = ")")
return CodeBlock.Builder()
.add("%T", type)
.add(argsCode)
.build()
}
val className = ClassName("", "StateType1")
val codeBlock = CodeBlock.of("%L", PropertySpec.builder("outputState", className)
.initializer(createConstructorCall(className, "iouValue", "ourIdentity", "otherParty"))
.build())
assertThat(codeBlock.toString()).isEqualTo("""
|val outputState: StateType1 = StateType1(iouValue, ourIdentity, otherParty)
|""".trimMargin())
In the second example, we don't really provide anything special, pass your code as a String and feel free to use placeholders to parameterize if needed:
val className1 = ClassName("", "TransactionBuilder")
val codeBlock1 = CodeBlock.of("%L", PropertySpec.builder("txBuilder", className)
.initializer(
"%T(notary = notary)\n.addOutputState(outputState, TEMPLATE_CONTRACT_ID)",
className1)
.build())
assertThat(codeBlock1.toString()).isEqualTo("""
|val txBuilder: StateType1 = TransactionBuilder(notary = notary)
| .addOutputState(outputState, TEMPLATE_CONTRACT_ID)
|""".trimMargin())

How to use a dynamically-determined Type as parameter to a Lambda<Func<>>?

I am dynamically creating a Lambda expression (based on user input but at the moment using dummy values for a proof-of-concept) for a type which I will only know at runtime. I therefore need to pass the T portion of the Func<T,TResult> as a dynamic type, since I won't know the type until runtime (TResult will always be a bool).
It seems that I cannot pass in a Type variable or use typeof with generics. Basically I'm trying to do something like this:
// (f => f.Baz == 1)
Type theType = Type.GetType("Foo");
ParameterExpression pe = Expression.Parameter(theType, "f");
Expression left = Expression.Property(pe, theType.GetProperty("Baz"));
Expression right = Expression.Constant(1);
Expression expr = Expression.Equal(left, right);
// This works fine but uses a hard-coded type, which I won't know until runtime:
// var lambda = Expression.Lambda<Func<Foo,bool>>(expr, new ParameterExpression[] { pe }).Compile();
var lambda = Expression.Lambda<Func<theType, bool>>(expr, new ParameterExpression[] { pe }).Compile();
However, I cannot use the variable theType as the T portion of the Func. How can I fix this?
No you can't.
For example, in C#, you can't:
Type t = typeof(int);
List<t> list = new List<t>();
or
object list = new List<t>();
Unless you use reflection, but then you have to put the list in an object, and you can use it only through reflection.
So if you want you can save your Func<> in an object (or a dynamic) but nothing more.
What you COULD do is always return Func<object, bool> and cast the object to the desidered type IN the lambda function (so use a Expression.Convert(pe, theType));
Or you could use the dynamic:
// lambda == Func<Foo, bool>
dynamic lamdba = Expression.Lambda(expr, new ParameterExpression[] { pe }).Compile();
bool res = lambda(myvalue);
or
// lambda == Func<Foo, bool>
Delegate lamdba = Expression.Lambda(expr, new ParameterExpression[] { pe }).Compile();
bool res = (bool)lambda2.DynamicInvoke(t);
To be taken "not as real" some benchmarks (in StopWatch.Ticks, look at them only for proportions) (Release Mode + Start Without Debugging + some useless cycles so that they are "hot"):
236384685 dynamic
56773593 Func<object, bool> + cast
10556024247 DynamicInvoke
as a note, Func<Foo, bool> has the same speed, so there isn't any speed lost in the extra cast.
You can see the code here http://ideone.com/qhnVP3