Allow an array of lesser length to be passed to functions.
contract A:
def test(b: address[4]): modifying
...
a: address[2]
A(x).test(a)
Should work.

So the call will pad the array? How would it pad it?
It would pad in the same way as an assignment would. Basically allowing this would save this boilerplate scenario:
a_list: address[10]
b_list: address[2]
b_list[1] = alist[1]
b_list[2] = alist[2]
@jacqueswww @fubuloubu are we sure that we don't want this to be something that has to be a bit more explicit? Like by creating an internal function extend(a, n, v=0), that takes two required parameters, and one optional parameter.
The first parameter "a" would be the input list to be extended, the second parameter "n" would be the number of entries to extend the given list by, and the third, optional, parameter "v" would be the value to extend with, which would have a default value of 0.
@jakerockland we have default args already, which is what I think you're suggesting. It works pretty well.
My issue is that I might have a function that batches an operation (say, letting me mint up to 64 NFTs at once), but I have to give it something that is exactly the size required or the operation will fail.
This is more of an ABI thing to be honest, we need a way to specify the difference between something that has to be exactly length N and something that could be up to length N but might be less (e.g. "max length" is |N`). Especially important given ABIv2 and people writing EIPs that use dynamically sized arrays for their function arguments.
@fubuloubu What do you mean by you have default args already? What I was suggesting was a bit different than the language just supporting default args, the idea was a built-in function that allows you to easily extend an array of length A to length B.
Here's a bit of example code to clarify:
@private
def foo(bar: uint256[4]) -> uint256:
m: uint256 = 0
for i in range(4):
if bar[i] > m:
m = bar[i]
return m
@public
def foobar() -> uint256:
a: uint256[2] = [1, 2]
b: uint256[4] = extend(a, 2)
m: uint256 = self.foo(b)
return m
Or just tweaking the original excerpt from @jacqueswww, something like:
contract A:
def test(b: address[4]): modifying
...
a: address[2]
A(x).test(extend(a, 2))
However, given the use case you just described, I'm not sure how optimal my proposal is.
I think a way to show you what may be problematic is an example like this:
def foo(bar: uint256[4]) -> uint256:
m: uint256 = 0
for i in range(bar):
if i > m:
m = i
return m
How do I pass something of size 2 to that that doesn't over-iterate on bar?
Oh yeah that is definitely problematic, that’s actually a good example of why I’m thinking an extend function might be helpful. 😅
On Dec 13, 2018, 2:45 PM -0700, Bryant Eisenbach notifications@github.com, wrote:
I think a way to show you what may be problematic is an example like this:
def foo(bar: uint256[4]) -> uint256:
m: uint256 = 0
for i in range(bar):
if i > m:
m = i
return m
How do I pass something of size two to that that doesn't over-iterate on bar?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
I think the best case would be to write something that ends up looking a lot like what we do with bytes[N] (where there is a len variable). This would probably be something specific to input/output parameters only.
Maybe something like uint256[:len] (up to len in size)? It parses...
>>> ast.parse('def foo(a: uint256[:4]): pass')
<_ast.Module at 0x7f7c9d4edba8>
We could also have that specify a min size:
def foo(a: uint256[2:4]):
for i in a:
# Runs a minimum of twice and a maximum of 4 times
# Produces ABI type: 'uint256[]', with optionals 'min=2', and 'max=4'
Probably pretty insidious though maybe
Hrm yeah haha I'm a bit torn, on one hand I think its an elegant way to handle these cases, on the other it does feel pretty magical/isn't the most intuitive to understand what is going on because in Python syntax that would be used for slicing, not type annotating, right?
Yup! Hopefully I've reframed the real problem I see better. It's not about making the parameter larger to fit, it's about allowing the parameter to be smaller in the first place.
Yeah the reframing is very helpful, thank you 😊I think we were talking past each other a bit but I'm on the same page now 😅
Going off your suggestion above, what're your thoughts on something like this:
def foo(a: uint256[2...4]):
for i in a:
# Runs a minimum of twice and a maximum of 4 times
# Produces ABI type: 'uint256[]', with optionals 'min=2', and 'max=4'
Could pre-parse the ... to : and then it parses fine. Also going about it this way would in-turn remove ... from Vyper syntax which is probably a reasonable thing to do anyway as it seems better to make people use pass, which is much more explicit and readable and ....
We decided that we won't support auto padding. However the following syntax should work, if not - it should be implemented:
b: uint256[2] = [1, 2]
a: uint256[10] = b
OR
b: uint256[2] = [1, 2]
a: uint256[10] = extend(b, 8)
For dynamic arrays we need to create a separate proposal.
Added proposal #1440 for dynamic arrays from this conversation