Is there a default method that gets called when I try to cast an object into a string? (E.g. toString in Java or __str__ in Python.) I want to be able to do the following with an array of Objects, but some of them might be nil:
for item in array {
writeln(item : string);
}
First of all, casting nil to string isn't necessarily a problem:
class C {
var x:int;
}
var array = [ new C(1), nil:C, new C(2) ];
for item in array {
writeln( item : string );
}
outputs
{x = 1}
nil
{x = 2}
Secondly, if you did want to customize the output of your class C, you'd write a writeThis method (or a readWriteThis method). See The readThis(), writeThis(), and readWriteThis() Methods. The writeThis method will be called both for cast to string and also for normal I/O. For example:
class C {
var x:int;
proc writeThis(writer) {
writer.writef("{%010i}", x);
}
}
var array = [ new C(1), nil:C, new C(2) ];
for item in array {
writeln( "writing item : string ", item : string );
writeln( "writing item ", item);
}
outputs
writing item : string {0000000001}
writing item {0000000001}
writing item : string nil
writing item nil
writing item : string {0000000002}
writing item {0000000002}
There is more I could say about why it works this way, what it might do in the future, and the limitations of the current strategy... but a mailing list would be a better place for such discussion if you'd like to have it.
Related
What happens is that I have a class called Drawing with Equatable as follows :
class Drawing extends Equatable {
final List<CanvasPath> canvasPaths;
const Drawing({
this.canvasPaths = const [],
});
#override
List<Object?> get props => [canvasPaths];
Drawing copyWith({
List<CanvasPath>? canvasPaths,
}) {
return Drawing(
canvasPaths: canvasPaths ?? this.canvasPaths,
);
}
}
I know I cannot initialize the list itself in the following way canvasPaths = newList; because it is final, however I use copyWith to attach it to the variable I have created in the following way :
class DrawingBloc extends Bloc<DrawingEvent, DrawingState> {
// Variable global in Bloc, like cached
final Drawing _drawing = const Drawing();
DrawingBloc() : super(const DrawingState()) {
on<StartDrawing>((event, emit) {
// ! i cant do
// _drawing.canvasPaths.add(event.canvasPath);
// ! or
// _drawing.canvasPaths.last = event.canvasPath;
// Create a new list
final newList = _drawing.canvasPaths.toList();
newList.add(event.canvasPath);
print(newList);
_drawing.copyWith(
canvasPaths: newList,
); // using the copyWith but when i print...
print(_drawing);
emit(state.copyWith(
status: DrawingStatus.success,
currentDrawing: _drawing.canvasPaths,
));
});
}
}
Result :
I would like to know why the copyWith does not show or does not work, I have to say that I use equatable because the list is compared.
But if I add it in the global class, it show this :
flutter Cannot add to an unmodifiable list
copyWith returns a new instance. it doesn't magically turn itself into a copy. so instead of
print(newList);
_drawing.copyWith(
canvasPaths: newList,
); // using the copyWith but when i print...
print(_drawing);
you could maybe do
print(newList);
var newDrawing = _drawing.copyWith(
canvasPaths: newList,
); // using the copyWith but when i print...
print(newDrawing);
Though that wouldn't help your situation probably. I'm not familiary with Equatable but couldn't you do
this.canvasPaths = [],
instead of
this.canvasPaths = const [],
or is it required to be a const? Because if you leave the const you could do
_drawing.canvasPaths.add(event.canvasPath);
just fine
I have a parent component file with one list object.
<h3>Create Movie</h3>
<MovieForm Movie="Movie" NotSelectedGenres="NotSelectedGenres" OnValidSubmit="SaveMovie"/>
#code {
private Movie Movie = new Movie() ;
private List<Genre> NotSelectedGenres = new List<Genre>()
{
new Genre()
{
Id = 1, Name = "Action"
},
new Genre()
{
Id = 2, Name = "Comedy"
},
new Genre()
{
Id = 3, Name = "Drama"
}
} ;
private void SaveMovie()
{
Console.WriteLine("this works") ;
}
}
then I insert child component named 'MovieForm' in it.
And then on debug mode, When I checked the length of 'NotSelectedGenres' it said total 4. (in child component)
[Parameter]
public List<Genre> SelectedGenres { get ; set ; } = new List<Genre>() ;
it has one more with value of 'null' than the original data set.
NotSelectedGenres
_items BlazorMoves.Shared.Entities.Genre[](4)
0 BlazorMoves.Shared.Entities.Genre
1 BlazorMoves.Shared.Entities.Genre
2 BlazorMoves.Shared.Entities.Genre
3 null
length 4
Is this the right thing?
As soon as you add the first item to a List in .NET, it internally allocates an array of size 4. The allocated size increases automatically as required.
the Count property should return the correct number of items in the list, while Capacity returns the current internal size allocated.
List<> docs
I have created a TextFormField in flutter. I have a class named ParticipantsData with a few properties listed. I can access and store values in all of those properties by making an object of ParticipantsData class in another class named "RegistrationForm". However I am unable to store data in the properties that are of type List even after having initialized them.
I have tried:
- List.filled()
- =[]
- =[""]
- List.generate()
- List()
- List<String>()
- List<String>(length)
I have changed my code multiple times over and tried many methods but nothing seems to work. I don't post here much because I usually find solutions on stackoverflow but this time I couldn't find anything.
Unable to post the whole code because it is too long. Below is the relevant code:
ParticipantsData class:
class ParticipantsData {
List name = []; //members
bool paymentstatus = false; //payment
String email = ""; //email
String address = ""; //address
List contact = []; //contact
String collegename = ""; //collegename
String password = ""; //password
String teamname = ""; //teamname
var modules = List<String>(6); //modules
ParticipantsData({
this.name,
this.email,
this.contact,
this.collegename,
this.address,
this.modules,
this.password,
this.paymentstatus,
this.teamname,
});
}
Below is the relevant code for Register class:
class _RegistrationForm extends State<RegistrationForm> {
final ParticipantsData data = new ParticipantsData();
//This is the onSaved method of a TextFormField, which is in a loop.
(String value) { //Tried this...
data.name[i + 1] = value;
print('${data.name[i + 1]}');
}),
(String value) { //And this too...
data.name.add(value);
print('${data.name[i + 1]}');
}),
The assigned values become null when initialized inside the constructor. If you don't include the fields in the constructor, they will not reset to null.
However, you may want to assign the values in the constructor and want some default value if the field is not provided while creating the instance. Here is how to do so:
class MyClass {
// Don't initialize here
List x;
int y;
MyClass({
this.x,
this.y = 10, // If y is not assigned, it will take a default value of 10
}) {
// Constructor body
this.x = this.x ?? []; // If x is not assigned, it will take a value of []
}
}
Notice that y can be provided with the default value directly as 10 is a constant value. You can only assign constant default values in the constructor parameter list. Since [ ] is not a constant expression or value, it can't be directly assigned as the default value hence, you need to define the constructor body assigning x = [ ] if x is null.
this.x = this.x ?? [];
You can initialize the others in a similar way.
I'm trying to add an element list to the list of string, but I found Kotlin does not have an add function like java so please help me out how to add the items to the list.
class RetrofitKotlin : AppCompatActivity() {
var listofVechile:List<Message>?=null
var listofVechileName:List<String>?=null
var listview:ListView?=null
var progressBar:ProgressBar?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_retrofit_kotlin)
listview=findViewById<ListView>(R.id.mlist)
var apiInterfacee=ApiClass.client.create(ApiInterfacee::class.java)
val call=apiInterfacee.getTaxiType()
call.enqueue(object : Callback<TaxiTypeResponse> {
override fun onResponse(call: Call<TaxiTypeResponse>, response: Response<TaxiTypeResponse>) {
listofVechile=response.body()?.message!!
println("Sixze is here listofVechile ${listofVechile!!.size}")
if (listofVechile!=null) {
for (i in 0..listofVechile!!.size-1) {
//how to add the name only listofVechileName list
}
}
//println("Sixze is here ${listofVechileName!!.size}")
val arrayadapter=ArrayAdapter<String>(this#RetrofitKotlin,android.R.layout.simple_expandable_list_item_1,listofVechileName)
listview!!.adapter=arrayadapter
}
override fun onFailure(call: Call<TaxiTypeResponse>, t: Throwable) {
}
})
}
}
A more idiomatic approach would be to use MutableList instead of specifically ArrayList. You can declare:
val listOfVehicleNames: MutableList<String> = mutableListOf()
And add to it that way. Alternatively, you may wish to prefer immutability, and declare it as:
var listOfVehicleNames: List<String> = emptyList()
And in your completion block, simply reassign it:
listOfVehicleNames = response.body()?.message()?.orEmpty()
.map { it.name() /* assumes name() function exists */ }
Talking about an idiomatic approach... 🙄
When you can get away with only using immutable lists (which means usually in Kotlin), simply use + or plus. It returns a new list
with all elements of the original list plus the newly added one:
val original = listOf("orange", "apple")
val modified = original + "lemon" // [orange, apple, lemon]
original.plus("lemon") yields the same result as original + "lemon". Slightly more verbose but might come in handy when combining several collection operations:
return getFruit()
.plus("lemon")
.distinct()
Besides adding a single element, you can use plus to concatenate a whole collection too:
val original = listOf("orange", "apple")
val other = listOf("banana", "strawberry")
val newList = original + other // [orange, apple, banana, strawberry]
Disclaimer: this doesn't directly answer OP's question, but I feel that in a question titled "How to add an item to a list in Kotlin?", which is a top Google hit for this topic, plus must be mentioned.
If you don't want or can't use array list directly use this code for add item
itemsList.toMutableList().add(item)
itemlist : list of your items
item : item you want to add
instead of using a regular list which is immutable just use an arrayListof which is mutable
so your regular list will become
var listofVehicleNames = arrayListOf("list items here")
then you can use the add function
listOfVehicleNames.add("what you want to add")
you should use a MutableList like ArrayList
var listofVechileName:List<String>?=null
becomes
var listofVechileName:ArrayList<String>?=null
and with that you can use the method add
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/add.html
For any specific class, the following may help
var newSearchData = List<FIRListValuesFromServer>()
for (i in 0 until this.singleton.firListFromServer.size) {
if (searchText.equals(this.singleton.firListFromServer.get(i).FIR_SRNO)) {
newSearchData.toMutableList().add(this.singleton.firListFromServer.get(i))
}
}
val listofVechile = mutableListOf<String>()
Declare mutable list like that and you will be able to add elements to list :
listofVechile.add("car")
https://kotlinlang.org/docs/collections-overview.html
I am currently having a list of obeject defined as:
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
... code below
}
the Tool data class is defined as:
data class Tool(
var id: String = ""
var description: String = ""
var assignedTo: String = ""
)
the Updated data class is defined as:
data class Updated(
var id: String = ""
var assignedTo: String = ""
)
Basically, I parse the list updateTools and if I found a id match in tools, I update the assignedTo field from the Tool type object from tools by the one from updateTools
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
updateTools.forEach{
val idToSearch = it.id
val nameToReplace = it.name
tools.find(){
if(it.id == idToSearch){it.name=nameToReplace}
}
}
return tools
}
it's not working but I do not see how to make it easier to work. I just started kotlin and I feel that it's not the good way to do it
any idea ?
Thanks
First of all:
you're not assigning assignedTo, you're assigning name...
in the predicate passed to find, which
should only return a Boolean value to filter elements, and
should probably not have any side effects,
those should be done later with a call to i.e. forEach.
Additionally, your constructor parameters to the data class are normal parameters, and as such, need commas between them!
Your last code block, corrected, would be:
updateTools.forEach {
val idToSearch = it.id
val nameToReplace = it.name
tools.find { it.id == idToSearch }.forEach { it.assignedTo = nameToReplace }
}
return tools
I'd do it like this (shorter):
updateTools.forEach { u -> tools.filter { it.id == u.id }.forEach { it.assignedTo = u.name } }
This loops through each update, filters tools for tools with the right ID, and sets the name of each of these tools.
I use forEach as filter returns a List<Tool>.
If you can guarantee that id is unique, you can do it like this instead:
updateTools.forEach { u -> tools.find { it.id == u.id }?.assignedTo = u.name }
firstOrNull returns the first element matching the condition, or null if there is none. Edit: it seems find is firstOrNull - its implementation just calls firstOrNull.
The ?. safe call operator returns null if the left operand is null, otherwise, it calls the method.
For = and other operators which return Unit (i.e. void, nothing), using the safe call operator simply does nothing if the left operand is null.
If we combine these, it effectively sets the name of the first element which matches this condition.
First, you're missing comma after properties in your data classes, so it should be:
data class Tool(
var id: String = "",
var description: String = "",
var assignedTo: String = ""
)
data class Updated(
var id: String = "",
var assignedTo: String = ""
)
As for second problem, there're probably number of ways to do that, but I've only corrected your idea:
fun updateList(tools: List<Tool>, updateTools: List<Updated>): List<Tool> {
updateTools.forEach{ ut ->
tools.find { it.id == ut.id }?.assignedTo = ut.assignedTo
}
return tools
}
Instead of assigning values to variables, you can name parameter for forEach and use it in rest of the loop.