Explain this solidity statement - solidity

I'm new to solidity and I came across the following statement:
address[] memory path = new address[](2);
Someone please break it down for me. Specifically, what does new address[](2) do?
TIA

It initializes new dynamic-length array variable called path
items are of type address
the array is stored in memory, non-persistent data location that is accessible only during the transaction
The right-side of the expression new address[](2) initializes the array with 2 empty items.
In Solidity, there is a difference between dynamic-length and fixed-length arrays. So if your function is expected to return array[] (dynamic-length), the compiler doesn't allow you to return array[2] (fixed-length).
Because of how the memory is structured, it's not possible to resize an array in memory. (However you can resize a storage array.) So this approach is used when you need to return a dynamic-length array. You need to initialize it in memory first with a predefined amount of empty values, and then rewrite those values. See this post for a code example.

Related

Weird behavior when set Array of Strings to HashMap in Kotlin

I'm tryna add to HashMap Array of Strings but instead of normal Array of String I see only address in memory of String in console.
val map = mapOf<String, Array<String>>()
val list = listOf("sport")
val array = list.toTypedArray()
map["key"] to array
And Array after this operation converts in smth like this — [Ljava.lang.String;#518ed9b4
But expected to see this kind of behavior:
map["key"] -> array("sport")
What's the problem might be with this sample of code?
Arrays in Java/Kotlin don't have a good automatic conversion to strings (technically, their implementation of toString()). What you see is your array, but instead of showing the contents, it only says it is an array of strings and shows the memory address.
To show the contents of an array you can use builtin contentToString() extension or wrap it into a list:
println(arrayOf("sport").contentToString())
println(arrayOf("sport").asList())
BTW, I believe there is a mistake in your example. map["key"] to array doesn't do anything, it should be probably map["key"] = array. Also, map in your example is read-only, you can't add items to it. However, as you already got to the point you print an array, I assume your real code is a little different.

Solidity memory in a function

Hi I am new to solidity and I am wondering why we use the keyword memory when declaring a function, what happens if we choose not to use it? For example
function createObject(string _name, uint _dna) public {
object.push(Object(_name, _dna));
}
instead of
function createObject(string memory _name, uint _dna) public {
object.push(Object(_name, _dna));
if you don't write it, easily it will give error
Without the memory keyword, Solidity tries to declare variables in storage.
Much like RAM, Memory in Solidity is a temporary place to store data whereas Storage holds data between function calls. The Solidity Smart Contract can use any amount of memory during the execution but once the execution stops, the Memory is completely wiped off for the next execution. Whereas Storage on the other hand is persistent, each execution of the Smart contract has access to the data previously stored on the storage area.
That is, the structure of storage is set in stone at the time of contract creation based on your contract-level variable declarations and cannot be changed by future method calls. BUT -- the contents of that storage can be changed with sendTransaction calls. Such calls change “state” which is why contract-level variables are called “state variables”. So a variable uint8 storagevar; declared at the contract level can be changed to any valid value of uint8 (0-255) but that “slot” for a value of type uint8 will always be there.
If you declare variables in functions without the memory keyword, then solidity will try to use the storage structure, which currently compiles, but can produce unexpected results. memory tells solidity to create a chunk of space for the variable at method runtime, guaranteeing its size and structure for future use in that method.
memory cannot be used at the contract level. Only in methods.
The memory keyword tells Solidity to store the parameter in a certain place which allows you to change that parameter inside the function itself. Pretty much like RAM.
Calldata is the same but the parameter is immutable. It's better to use that if you don't plan on changing the parameter inside the function because it's more efficient.
Storage tells Solidity that the value is in the state of the smart contract. It's also more efficient than memory if the parameter is indeed in the state.
You can get more information about the difference between these 3 keywords in this article

Is type assignability too strict in JavaConstant.Dynamic.ofInvocation()?

I've read Rafael's article and am now doing awful, terrible things with JavaConstant.Dynamic. Mostly I'm getting a feel for how it works.
As part of these horrid experiments, I am turning an array of non-constant things into an array of JavaConstants. Then I'm invoking JavaConstant.Dynamic.ofInvocation(SOME_METHOD_THAT_ACCEPTS_A_VARARGS_OF_THINGS, javaConstantsArray).
So, for example, something like this:
static final JavaConstant toJavaConstant(final Glorp[] glorps) {
final JavaConstant[] javaConstants = new JavaConstant[glorps.length];
for (int i = 0; i < javaConstants.length; i++) {
javaConstants[i] = toJavaConstant(glorps[i]); // another version of this method that works on scalars
}
return JavaConstant.Dynamic.ofInvocation(SOME_METHOD_THAT_ACCEPTS_A_VARARGS_OF_THINGS, javaConstants);
}
ByteBuddy is telling me in the ofInvocation call that one of the JavaConstants in the varargs array I've passed it is not assignable to the parameter type of the SOME_METHOD_THAT_ACCEPTS_A_VARARGS_OF_THINGS. I can understand this, because strictly speaking a variable arity method accepts an array as its last parameter, and a JavaConstant is not an array. But given that the SOME_METHOD_THAT_ACCEPTS_A_VARARGS_OF_THINGS is ultimately resolved via the MethodHandle machinery with all of its argument adaptation and spreading tricks, I wonder: is this proactive assignability check "too much"? Should ByteBuddy take into account the varargs nature of the bootstrap method? Is there some other way to create an array or a list of an arbitrary number of scalar constants as a constant itself?
Yes, this was a bug and it will be fixed in Byte Buddy 1.10.18. Thanks for the patch!

Understanding Solr charTermAttr methods

I can across a copy methods from charTermAttr from the org.apache.lucene.analysis.tokenattributes.CharTermAttribute library.
Can anyone explain what copyBuffer and buffer does for charTermAttr? The documentation isn't very clear. If you could provide an example that would be great too!
CharTermAttributeImpl keeps internally a char array and a length variable that represents the internal term.
The copyBuffer method writes over this array by using the char array provided with the respective offset and length params.
The buffer method returns the internal array that you can directly modify. Additionally, you can get the term representation as a string by calling the attribute's toString method
Have a look at the javadocs for more details: http://lucene.apache.org/core/4_9_0/core/org/apache/lucene/analysis/tokenattributes/CharTermAttribute.html

d2: assigning ranges/iterators to array slices

Consider following code:
enum size = 16;
double[size] arr1 = [...];
double[size] arr2 = [...];
process = (double x) { return (x + 1); };
arr2[] = map!(process)(arr1[]); // here
I have trouble converting results of map back to my plain array. Problem applies not only to map, but also to take, repeat and all those fine tools from std.algorithm and std.range that operate on ranges.
On this assignment, I get Error: cannot implicitly convert expression (map(arr1[])) of type Result to double[]. How can I evaluate range to array without using
uint i = 0;
foreach (x; map!(process)(arr1[])) {
arr2[i] = x;
i++;
}
?
Additionally, can someone please explain, why I must call map!(process)(arr1[]) instead of map!(process)(arr1) with static arrays? Shouldn't static arrays be compatible with dynamic for means of iteration, or I don't get something?
Also, it seems that straightforward enumeration syntax foreach (index, item; sequence) does not work for ranges - are there workarounds? I guess the reason is the same as why ranges cannot be assigned to array slices.
Functions such as map and filter return ranges, not arrays, so simply assigning to an array isn't going to work any more than assigning a string to wstring is going to work. They're different types. And for many range-based functions (including map and filter), the ranges they return are actually lazy in order to avoid unnecessary computation, which makes them that much less compatible with an array. The solution is to use std.array.array, which takes a range and creates a dynamic array from it. So, you could do
auto arr = array(map!process(origArray));
However, I would advise not converting a range into an array before you actually need to, since it can result in unnecessary computations, and it means allocating a new array. If you actually need an array, then by all means, use std.array.array to convert the range, but operating on the range can often be more efficient if you don't need an actual array. However, if you want to convert the result to a static array as opposed to a dynamic one, you're probably better off just assigning each element in a loop (and maybe skipping map altogether), since using std.array.array will then have allocated a dynamic array that you won't be using once you've assigned to the static array. It's a waste of memory.
Also, be aware that using static arrays with range-based functions can be risky in that they must slice the static array to get a dynamic array for the range-based functions to process, and if that dynamic array escapes the scope that the static array was declared in, then you're leaking references to data which no longer exists. For example,
auto func()
{
int[5] arr;
return map!process(arr[]);
}
would be very bad. However, as long as you're done using the slice and nothing refers to it anymore (including any ranges that might have been created) before you exit the scope with the static array in it, you should be fine. It is something to be careful of though.
As for the question about having to slice static arrays, you really should ask that as a separate question, but two existing questions that relate to it are this one and this one. What it pretty much comes down to is that IFTI (Implicit Function Template Instantiation) instantiates using the exact type that it's given, and a static array is neither a dynamic array nor a range, so any templated function which specifically requires a dynamic array or a range will fail to compile with a static array. The compiler will implicitly slice static arrays to convert them to dynamic arrays for functions which explicitly take dynamic arrays, but those sort of implicit conversions don't happen with template instantiation, so you must explicitly slice static arrays to pass them to range-based functions.
As for the question about using foreach with indices and ranges, again, you shouldn't be asking multiple questions in the same question. Please post separate questions for each question that you have. What it comes down to though is that
foreach(elem; range)
{
//stuff
}
gets lowered to something close to
for(; !range.empty; range.popFront())
{
auto elem = range.front;
//stuff
}
And that doesn't involve indices at all. It could be change to create an index variable for you, but it doesn't always make sense for ranges to have their index iterating by one like that on every iteration (much as it usually would be fine), and so that hasn't been done. It's simple enough to add your own counter though.
{
size_t i;
foreach(elem; range)
{
//stuff
++i;
}
}
opApply does support using indices with foreach, but it isn't a range, and doesn't work with range-based functions.