New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cryptic type error for multiple return values #164

Closed
nmushegian opened this Issue Oct 21, 2015 · 12 comments

Comments

Projects
None yet
4 participants
@nmushegian
contract MultiReturner {
    function get() returns (bytes value, bool ok) {
        bytes memory val;
        return (val, true);
    }
}

contract MultiRetUser {
    function try_to_get() {
        var mr = new MultiReturner();
        bytes memory value;
        bool ok;
        (value, ok) = mr.get();
    }
}
lang/multiret_test.sol:14:23: Error: Type bool is not implicitly convertible to expected type tuple(bytes memory,bool).
        (value, ok) = mr.get();
                      ^

same error if I switch the order. No error if I use bytes32 instead of bytes.

@chriseth

This comment has been minimized.

Show comment
Hide comment
Contributor

chriseth commented Oct 21, 2015

@chriseth chriseth closed this Oct 21, 2015

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Oct 21, 2015

Contributor

I just realised that I should probably explain why this happens:
The EVM is unable to read variably-sized data from external function calls. Because of that, such types are removed from the signature of functions.
Note that on the other hand, it is possible to return variably-sized data, it just cannot be read from within the EVM.

Contributor

chriseth commented Oct 21, 2015

I just realised that I should probably explain why this happens:
The EVM is unable to read variably-sized data from external function calls. Because of that, such types are removed from the signature of functions.
Note that on the other hand, it is possible to return variably-sized data, it just cannot be read from within the EVM.

@nmushegian

This comment has been minimized.

Show comment
Hide comment
@nmushegian

nmushegian Oct 22, 2015

I don't understand how this can be an EVM restriction, if it can read fixed-size data of arbitrary size when you know the type.

I don't understand how this can be an EVM restriction, if it can read fixed-size data of arbitrary size when you know the type.

@nmushegian

This comment has been minimized.

Show comment
Hide comment
@nmushegian

nmushegian Oct 22, 2015

The only explanation I can think of is that the evm requires you to say the size of the calldata buffer for the return value when you are making the call. What happens if you just say that it has size 2^256, then parse the return value lengths yourself?

The only explanation I can think of is that the evm requires you to say the size of the calldata buffer for the return value when you are making the call. What happens if you just say that it has size 2^256, then parse the return value lengths yourself?

@Nashatyrev

This comment has been minimized.

Show comment
Hide comment
@Nashatyrev

Nashatyrev Oct 22, 2015

Member

Chris,
can you please elaborate more on this?
Does it mean that absolutely no EVM contracts (Solidity or others) can read returned dynamic type values from internal calls?
Thanks!

Member

Nashatyrev commented Oct 22, 2015

Chris,
can you please elaborate more on this?
Does it mean that absolutely no EVM contracts (Solidity or others) can read returned dynamic type values from internal calls?
Thanks!

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Oct 22, 2015

Contributor

Before making the call, you have to specify the location where the return value should be put (position and length). The problem is that you already have to pay for memory usage before you make the call, so just specifying 2**256 for the length will use up all your gas.

These restrictions are not specific to Solidity.

Contributor

chriseth commented Oct 22, 2015

Before making the call, you have to specify the location where the return value should be put (position and length). The problem is that you already have to pay for memory usage before you make the call, so just specifying 2**256 for the length will use up all your gas.

These restrictions are not specific to Solidity.

@nmushegian

This comment has been minimized.

Show comment
Hide comment
@nmushegian

nmushegian Oct 22, 2015

This is another argument for supporting a feature like
low_level_call( bytes calldata, uint buffer_size ) returns (bytes data, bool ok)
you can detect whether your dynamically-sized type is readable or not

This is another argument for supporting a feature like
low_level_call( bytes calldata, uint buffer_size ) returns (bytes data, bool ok)
you can detect whether your dynamically-sized type is readable or not

@nmushegian

This comment has been minimized.

Show comment
Hide comment
@Nashatyrev

This comment has been minimized.

Show comment
Hide comment
@Nashatyrev

Nashatyrev Oct 22, 2015

Member

So if there is a contract returning int[] I can use it only via ABI but have no chances to call it from another contract. Quite sad limitation.

Member

Nashatyrev commented Oct 22, 2015

So if there is a contract returning int[] I can use it only via ABI but have no chances to call it from another contract. Quite sad limitation.

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Oct 22, 2015

Contributor

@nmushegian low_level_call will not help here - because even with a low level call there is no way to reserve space in memory whose size depends on a value that is only computed in the function that is called.

@Nashatyrev you are right. We plan to remove this limitation in Ethereum 2.0.

Contributor

chriseth commented Oct 22, 2015

@nmushegian low_level_call will not help here - because even with a low level call there is no way to reserve space in memory whose size depends on a value that is only computed in the function that is called.

@Nashatyrev you are right. We plan to remove this limitation in Ethereum 2.0.

@nmushegian

This comment has been minimized.

Show comment
Hide comment
@nmushegian

nmushegian Oct 22, 2015

What I meant was that I specify the size in the caller. I'm that if the callee tries to write too much to the return data, it just truncates it or crashes the transaction. So the caller should be able to interpret it as a dynamic array if I insist, if the array size is in the first word then I can check if it was too big and know that it failed. Then in the callee I just return (bytes, bool) and don't worry about the size.

What I meant was that I specify the size in the caller. I'm that if the callee tries to write too much to the return data, it just truncates it or crashes the transaction. So the caller should be able to interpret it as a dynamic array if I insist, if the array size is in the first word then I can check if it was too big and know that it failed. Then in the callee I just return (bytes, bool) and don't worry about the size.

@raineorshine

This comment has been minimized.

Show comment
Hide comment
@raineorshine

raineorshine Aug 5, 2016

Contributor

Would it be possible to just get a better error message in the mean time? This seems like a common gotcha.

Contributor

raineorshine commented Aug 5, 2016

Would it be possible to just get a better error message in the mean time? This seems like a common gotcha.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment