Delphi SOAP Client adding items to dynamic array - arrays

I'm currently developing a client for a SOAP service.
The WSDL import works fine, but I'm facing the problem that I need to add items to a dynamic array.
The declaration in delphi:
Array_Of_attributWS = array of attributWS;
dienstleistungWS = class(TRemotable)
private
[..]
public
[..]
published
property attributeWS: Array_Of_attributWS
Index(IS_OPTN or IS_UNBD or IS_NLBL or IS_UNQL)read GetattributeWS
write SetattributeWS stored attributeWS_Specified;
I want to add an item to attributeWS from an other unit.
To add an item I use this code:
SetLength(dynArray, Length(dynArray)+1);
dynArray[High(dynArray)] := item;
But it wont let me, I get the following error:
E2197 Constant object cannot be passed as var parameter
Is there a way to add an item easy to the dynamic array?
Or is there a way to cast the array to a list so that I can just do .Append(item)?
Delphi Version XE6
Thanks!

If you check the SetattributeWS implementation you will see it simply gets your dynamic array as a const parameter, stores it and marks an internal boolean variable as true (indicating the parameter has been informed).
The const part is the one that causes the E2197 error you are seeing.
The best option is to use a local dynamic array variable of the same type and then:
set its length to the actual length of attributeWS + 1.
copy the original items from attributeWS to the local variable, and then add the new item.
assign this variable to the attributeWS property.
Actually, it would be better to not assign the dynamic array to the request property until you have it filled with all the necessary elements, but that may depend on your needs.

Related

Adding a new Entry in a Struct holding a TArray as Member value doesn’t update it’s entries

I am currently working on a Character Customization System where a HUDLayout dynamically create Widgets based on a set of Skins available for the Character Selected. A Skin is represented as a Struct called MaterialInstanceContainer and holds a TArray. Player can mix and match their selection according to the Body Parts they select. In order to achieve the final result, I want to create a TMap<string, MaterialInstanceContainer> so that I can map each BodyParts available for selection with the individual material instance targeting the same BodyPart.
ISSUE: My issue is as follow, when I try to foreach over my collection of Material Instances inside my Container, I do a string comparison and if the output is valid, I can then break my struct to access the Material Instance Array and ADD to it however, at the very end of the process, the length of the array inside Material Container is still at zero.
How can I add a new entry in the array that my Material Container Struct hold?
Thanks!
enter image description here
The issue here is actually pretty straight forward: in Blueprints when you 'Find' a member of Map you are not getting it by-reference, instead you get the copy.
This is exactly what happens at the end of your nested loop: You get a copy, you add item to it, and when another iteration kicks-in the copy gets terminated.
And here on my side it returns exactly the same result as expected:
The fix for that would be easy:
After editing a Copy, you can overwrite the Map member by its copy (via 'Add' node).
But in your case it will be more tricky. You cannot just plug the same BreakStruct/Array node that you just used because it would call whole Find sequence again which creates another copy. Look
If you are confused. This code actually looks like this for Unreal's point of view.
So you have to store the the Struct in local variable first, then perform any operations on it and after everything is done - overwrite the Map member by its locally stored copy. And the result is
Map member gets overwritten every time and everything is as it should be.
Well, almost... For some reason your code is stored in Macro. I think you have to change it to a Function to be able to create local struct variable. But it shouldn't be a problem in this specific case because in your code there is no logic that needs to be done in macro.
Hope, it helps

Uncaught Cannot convert Array to Object[][] when passing array of arrays to range.setValues()

Desired Behaviour
Populate Google Sheet with array of arrays from a Javascript file.
// in js file (within google apps script project)
var aoa = [["row_01_val01", "row_01_val02", "row_01_val03"],
["row_02_val01", "row_02_val02", "row_02_val03"]]; // etc
google.script.run.withSuccessHandler(console.log("success")).populateSpreadsheet(aoa);
// in code.gs
// define target_range (ignore discrepancies between example values above)
var target_range = active_sheet.getRange(2, 1, 834, 20);
// set values of target_range
target_range.setValues(aoa);
Current Behaviour
// chrome developer tools (firefox/firebug not supported at work)
Uncaught Cannot convert Array to Object[][]
Question
I'm unable to post more specific code due to work restrictions (cannot access SO from work, or take code home, hence the pseudo code), but are there any common 'gotchas' when it comes to passing an array of arrays from a Javascript file to Code.gs for use in setValues()?
What I've Tried
In the js file, console.log(typeof(aoa)) returns object just before passing it to populateSpreadsheet() within Code.gs, and then Logger.log(aoa) within populateSpreadsheet() also returns object
Example:
var outer_array = [];
inner_array = [1,2,3];
outer_array.push(inner_array);
typeof(outer_array);
"object"
I've tried to refactor the code several times, but am wondering if there are any common gotchas like size constraints, quotas, or timeouts or some other 'quirk' I haven't considered?
This question and answer, for example, required the array of arrays to be reconstructed before passing it to setValues() (I tried this but it didn't work in my instance):
https://stackoverflow.com/a/11066322/1063287
Another thing I considered is that I'm using splice()(MDN reference) to add some values to the inner array's within Code.gs, so I'm not sure if that somehow changes the type permissible to be passed to setValues()?

How to add and remove objects from an array in Eiffel

I am trying to make a CONTAINER class that maintains an array of CRITTER objects (that I have already created and tested. Note, there are various CRITTER subspecies, that are inheriting from the CRITTER super class). The aim is to add and remove CRITTER objects from this array. This is what the CONTAINER class looks like:
class
CONTAINER
create
make
feature
num: detachable INTEGER
list: ARRAY[CRITTER]
make
local
do
create list.make_empty
num := 0
end
addCritter(critter: CRITTER)
do
list.put(animal, num)
num := num + 1
end
removeCritter(critter: CRITTER)
do
list.put (list.at (num), ???) -- put last element in position of element to be removed
list.remove_tail (num) -- remove tail
num := num - 1
end
end
Two issues:
Firstly, I can instantiate the CONTAINER class inside APPLICATION, but when I call
create container.make
container.addCritter(myCritter)
I get a precondition, invalid index violation error on the second line. This may be because I have not set the upper and lower bounds of the array. However, when I try to do so, I get syntax errors. Which is the way to solve this issue?
Secondly, in order to remove an object from the array, it would help if I could get hold of the index value, but I can't see any function that does this, unless I am missing something.
ARRAYs are usually used for fixed-length containers. In your case, with lots of dynamic changes, it's better to use more dynamic structures, for example, ARRAYED_LIST. Similar to ARRAY it provides features to access items by their index, but there are also more convenient ones. New elements can be added by using feature extend. Old elements can be removed by using feature prune if only one element matching a given one needs to be removed, or prune_all, if all matching elements need to be removed. The word "matching" denotes either reference or object equality, depending on which comparison criteria is required: = or ~. The comparison criteria is changed using feature compare_objects.
Some general observations:
There is no need to track number of elements yourself, usually there is a feature count that provides this number.
Indexes in Eiffel usually start with 1, not 0.
The declaration detachable INTEGER is equivalent to INTEGER because INTEGER is expanded and all expanded types are attached regardless of any attachment marks.
The following discussion might also be useful:
How to initialise an array of objects in Eiffel?

Storing array data in firebase, and how ID's are generated

I have a set of objects in my firebase data that all have an array under them. When I create the initial object, I create the initial array with its first object with a line of code like this:
ref.child('items').set([{firstobject: id123}])
this seems to set the id to zero, as the first item in the array. However when I later try to push() a new item to the array with this line of code, I get a more complex id (ZwPiVMIrzbSdvfwxkts).
ref.child('items').push(someNewObject);
In your first line of code, you're calling the Firebase.set() method passing it a JavaScript array that contains a single object.
In your second line of code, you're calling the Firebase.push() method with an object.
Given that Firebase lists/collections are not the same as JavaScript arrays, you end up with a mismatch.
Unlike JavaScript arrays, Firebase's lists are architected to scale well in highly concurrent, multi-user scenarios. I'd recommend to use them instead of arrays from the start.
ref.child('items').push({firstobject: id123});
ref.child('items').push(someNewObject);
With this snippet, all your items will be stored under so-called push ids.

Make variable name using loop and string in PowerBuilder

I am interested if it is possible to make variable name in PowerBuilder using a loop and a string. For example:
long ll_go
string lst_new
for ll_go = 1 to 8
lst_new = "text" + ll_go
lst_new.tag = 5500
next
So, it should give me variables text1, text2..,.,text8 and I would be able to assign values for them. Let me know if anybody succeeded, thanks in advance
Your description is lacking some term precision.
If you actually want to dynamically create new variables as "variable in a powerscript subroutine or function" this is simply not possible.
If instead you want to create dynamically some new controls statictext or textedit objects in a window or visual userobject this is possible:
use a local variable of the type of the new object you need to create, e.g. static text
make it a live object (instantiate) with create
set the object properties to whatever you need
"attach" the new object to its parent (either a window or a visual userobject - though any graphicobject is possible with using the win32api SetParent function) with the OpenUserObject() method. Note that you cannot simply add it directly to the parent's Control[] array.
you can also keep the object in your own array for later convenience access to the created objects instead of looping on the Control[] array
once the object is attached it its parent, you can reuse the local variable to create another one
Here is an example:
//put this in a button clicked() event on a window
//i_myedits is declared in instances variables as
//SingleLineEdit i_myedits[]
SingleLineEdit sle
int i
for i = 1 to 8
sle = create singlelineedit
sle.text = string(i)
sle.tag = "text_" + string(i)
sle.height = pixelstounits(20, ypixelstounits!)
sle.width = pixelstounits(100, xpixelstounits!)
parent.openuserobject(sle, pixelstounits(10, xpixelstounits!), pixelstounits(22 * i, ypixelstounits!))
i_myedits[i] = sle //keep our own reference
next
An exemple of values access:
//put that in another button clicked() event
SingleLineEdit sle
int i
string s_msg
for i = 1 to upperbound(i_myedits[])
sle = i_myedits[i]
if i > 1 then s_msg += "~r~n"
s_msg += "edit #" + string(i) + " (" + sle.tag + ") says '" + sle.text + "'"
next
messagebox("Edits values", s_msg)
As you can see, one practicality problem is that you cannot refer to these controls by constructing the control's name like "text"+2, instead you must access the my edits[] array or loop through the controls and test their .tag property if you set it to something specific.
I do not think that it is possible. Workaround could be an array maybe.
Br. Gábor
I'd see two ways to do this, but they aren't as easy as it seems that you were hoping:
1. Control Array
First method would be to go through the control arrays (on windows, tabs and user objects). I'd create a function that took the control name as a string, then another that overloaded the same function and took control name and an array of windowobject. The string-only method would just call the string/array method, passing the string through and adding the window.Control as the second parameter. The string/array method would go through the array, and for each element, get the ClassDefinition. Pull the name off of it, and parse it apart the way you want it to match the string parameter (e.g. for w_test`tab_first`tabpage_first`cb_here, do you want cb_here to match, or tab_first`tabpage_first`cb_here?). Deal with matches as appropriate. When you find a control of type tab or user object, call the string/array function again with the Control array from that object; deal with success/fail returns as appropriate.
2. DataWindow
What you're describing works extremely well with DataWindows, and their Describe() and Modify() functions. Since you pass these functions only a string, you can build not only the control names, but the values they're set to as you would build any string. In fact, you can build multiple Modify() strings together (delimited by a space) and make a single call to Modify(); this is not only faster, but reduces window flicker and visible activity.
Don't fall into the trap of thinking that, since your data isn't from a database, you can't use a DataWindow. Create an external DataWindow, and simply use it with one row inserted during the Constructor event.
As you might guess, I'd strongly favour the DataWindow approach. Not only is it going to perform better, but it's going to provide a lot more flexibility when you want to move on and tag more control types than just static text. (You'll have to do some type casting even with one control type, but if you want to get into multiples, you'll need to start a CHOOSE CASE to handle all your types.)
Good luck,
Terry
You can't create a variable name in a script because the variables have to be declared before you can use them. With PBNI it's possible to generate a name the way you describe and then get a reference to a variable of that name that already exists but I don't think that's what you want. If you want to keep track of additional properties for your controls, just inherit a new user object from whatever it is (sle, mle, etc.) and add the properties you want. Then you can place your user object on a window and use the properties. Another approach is to use the control's Tag property. It holds a string that you can put whatever you want in. PFC uses this technique. Terry's DataWindow solution is a good approach for storing arbitrary data.
Yes, and there are more than one way to skin a cat.
Sounds like you have several properties so I'd use an array of custom non visual user objects, or an array of structures. Otherwise you could probably use something from the .NET framework like a dictionary object or something like that, or a datawidnow using an external datasource, where you can refer to column names as col + ll_index.ToString().
SIMPLE Example:
Make custom NVO with following instance variables, plus getter/setter functions for each, name it n_single_field
// add the properties and recommend getter and setter functions
public string myTag
public string myText
public int myTabOrder
...
// To USE the NVO define an unbounded array
n_single_field fields[]
// to process the populated fields
integer li_x, li_max_fields
// loop through field 1 through max using array index for field number
li_max_fields = upperbound(fields)
for li_x = 1 to li_max_fields
fields[li_x].myTag = 'abc'
fields[li_x].myText = 'text for field number ' + li_x.ToString()
fields[li_x].myTabOrder = li_x * 10
next
Maybe I'm oversimplifying if so let me know, if there is a will there is always a way. ;)

Resources