Solidity tutorial: returning structs from public functions

In the current version of Solidity (0.4.13, as of this writing), it’s impossible to return a struct from a public function. For example, if you attempt to compile the following code, you will get two errors, one for each function that tries to do so:

You can open this Gist in browser-solidity with the following link:

As you’ll see, the compiler complains about both functions, getBryn and getPerson:

TypeError: Internal type is not allowed for public or external functions.

Confirmed, it’s impossible to return structs.

However, if you’ve been coding in Solidity for a while, you might notice that the following works perfectly well:

Because the mapping is public, Solidity automatically generates a getter for this function. That’s odd, because the getter would have to return a Person struct, right? Let’s dig in a little bit deeper.

Let’s deploy the above contract and run the following Javascript code:

Okay, so what’s going on here?

Shouldn’t the compiler complain when we ask it to generate a getter for a mapping that returns a Person struct?

As it turns out, solc is smart enough to handle this case for us. Notice the return value from the invocation of project.people('0xdeadbeef'). It’s an array, which is how Solidity tuples are returned to Javascript land. Alright, so we know that the getter is not returning a struct, per se, but rather a tuple. This is a big clue!

When the compiler generates a getter for a mapping or an array where the element is a struct, it does something like the following:

As you can see, the getter simply breaks the struct down into a tuple. No internal types (like structs) are exposed. As a result, we get the functionality we desired with no compiler error. We simply have to be careful about the ordering of struct fields—if the order changes, we’ll have to change any code that interacts with this getter, since the order of the tuple values will change as well.

Knowing this, we can take a cue from Solidity’s implementation of this mapping getter when writing our own functions that return structs.

Returning arrays of structs

Sometimes we might need to return an array of structs to the caller. However, if we take the naïve approach, we’ll once again run into the same limitation—we can’t expose internal types.

We learned above that we can “destructure” a struct and return it as a tuple. To return an array of structs, we will do the same thing. Each value in the returned tuple will represent a field in the struct. But because we’re trying to return many structs (and therefore, many values for each field), each field in the tuple will be an array.

Check out the following code to get a better sense of how this might look:

Getting data back in this format is, admittedly, a pain to deal with on the frontend. Depending on your frontend data model, you may very well have to write functions to “rebuild” these structs from the data you receive. I’ve thrown together a quick example to show you how you might go about doing that:

Note that struct “destructuring” is (hopefully) a temporary workaround. Solidity’s behavior is expected to change at some point in the future, making this a bit more seamless.

Find me around the web:

Click to read more solidity Stories
Like what you read? Give Bryn Bellomy a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.