Vyper for Beginners — Functions

Welcome back to Vyper for Beginners! This lesson is dedicated to functions.

Vyper for Beginners Series

Functions

Functions are fundamental to programming. A function is a series of operations applied, in order, to a piece or pieces of data. Programmers should be familiar with the built-in functions of their programming language. As a program becomes more complex, programmers are encouraged to remember the phrase “never repeat yourself”. If you need to apply some operations to a set of data once, it is OK to include it inline in your main code block. However if you find yourself applying that same set of operations again in a different place, it’s in your interest to create a separate function for these operations, then reference this function whenever you need to repeat those operations.

In addition to being a container for reusable code, a smart contract function often represents a means for users and other contracts to interact. The familiar ERC-20 token actions transfer and approve are simply functions that are executed by the associate token’s smart contract.

A function often has a set of inputs and outputs, but either can be omitted to suit the function being written.

Vyper Function Requirements

Vyper requires the following when declaring a function:

  • A function must be declared with a visibility decorator
  • The function’s inputs and output must be declared with their associated data types
  • All return values must match the output data type
  • The functions must be declared in an order that avoids forward references (one function calling another that has not been defined yet)

Decorators

A decorator is a keyword with an @ symbol, placed above a function definition. The “decorator” description is taken directly from Python. In Python, a decorator allows a function to be “wrapped” by another function. This “wrapper” function modifies the behavior of the original function without having to directly modify its code.

I’m unfamiliar with the mechanism behind Vyper’s decorator keywords, but it provides the same behavior here. Adding one or more decorators allows you to restrict a function to execute only under certain conditions.

There are two visibility decorators that control who may initiate (call) the function:

  • @internal — the function is only accessible from within another function defined inside this contract
  • @external — the function is only accessible from outside the contract

There are four mutability decorators that control other aspects of the function:

  • @pure — the function does not perform any reads of the contract state or any variables defined within
  • @view — the function may perform reads of the contract state and variables, but does not modify the state
  • @payable — the function may receive Ether (or the equivalent native token)
  • @nonreentrant(<unique_key>) — this function, and all other functions that use the same key, may not be called externally more than once during the same transaction

Wherever @payable is omitted, @nonpayable is assumed, however specifying it does no harm and increases clarity.

Return Values

A function that returns a value must include that return value type in its definition.

Consider a function that finds a user’s balance. It is likely that uint256 is an appropriate return value type for this function.

A function can return any data type (value or reference), except for a mapping.

If a function does not return anything, the return statement may be omitted. If the function returns a value, a return statement must appear somewhere.

Calling Internal Functions

An internal function can only be called from within another function, and they are all accessed from the self object.

To execute an internal function called internal_test(), include the function call self.internal_test() inside another function.

Modifiers

Solidity developers are familiar with the concept of a modifier. A modifier is a short function that requires some condition to evaluate to True. This modifier name can be added to another function declaration. This behaves similarly to the decorators described above. A common example is the modifier onlyOwner which will execute a short check that checks this on each call of a function that includes onlyOwner in its function declaration:

modifier onlyOwner() {
        _checkOwner();
        _;
}

/**
 * @dev Returns the address of the current owner.
 */
function owner() public view virtual returns (address) {
    return _owner;
}

/**
 * @dev Throws if the sender is not the owner.
 */
function _checkOwner() internal view virtual {
    require(owner() == _msgSender(), "Ownable: caller is not the owner");
}

Vyper does not provide this feature for security reasons (it is more difficult to analyze what a function will do if is has a modifier).

However the same behavior could be easily implemented in Vyper by writing an internal function that asserts the same requirement:

@internal
def _checkOwner(addr: address):
    assert addr == self.owner, "NOT OWNER"

@external
def admin_function():
    self._checkOwner()
    [...]

Constructor

The constructor is a special function that is intended to be executed once. It can be used to set the initial values for storage and immutable variables. A common use for the constructor is to set a contract owner by storing the msg.sender value permanently.

A Vyper constructor is defined using the special __init__() function name. It must be marked @external and may not return any value. Here is a simple constructor that stores the contract owner’s address in two places.

# @version ^0.3

owner: address
OWNER: immutable(address)

@external
def __init__():
    self.owner = msg.sender
    OWNER = msg.sender

Vyper allows you to record some values permanently in the deployed bytecode instead of consuming a storage slot. This results in a cheaper deployment gas cost for variables that will never change.

Fallback Function

By default Vyper will construct a fallback function that automatically reverts. This is useful as a mechanism to fail when a function cannot be found that matches the calldata. The fallback function is defined using the __default__() name.

If you want your function to be always reject basic Ether transfers, as well as unknown functions, define it as such:

@external
def __default__():
    raise

This “fail-proof” fallback will prevent users from sending Ether to the contract by mistake.

Photo of author

Written By BowTiedDevil

Degenerate coder, open source software maximalist, engineer, turbo autist.

Disclosure

This article may contain links to third-party websites or other content for information purposes. BowTiedIsland may receive a commission at no cost to you if you purchase a product after clicking one of these links. The Third-Party Sites are not under the control of BowTiedIsland, and BowTiedIsland is not responsible for the content of any Third-Party Site. All information contained herein is the opinion of the writer and does not constitute financial advice. We aim to act as a neutral third party and aid in your research and analysis.


The Jungle


Crypto, Investing, and E-Commerce with BowTied Bull

The future is internet based, therefore we have a triangle based approach with crypto, e-commerce business making and Investing in traditional assets

The Culture War with BowTiedRanger

Whether you’re a political junkie or just interested in current events. 

You’ve come to the right place for analysis of the most relevant current events and political issues.

Fitness With BowTiedOx

BowTiedOx provides you a place to find all of his latest programs and guides.

Weekly newsletters that cover fitness, health, and mindset, all grounded in the fundamentals of physiology.

Media Production with BowTied Turkey and BowTied Tamarin

Video is no longer optional.

Don’t get left behind.

Your brand deserves professional videos to engage your audience.

Art & Graphic Design with BowTied Patriot

BowTied Patriot is a graphic artist who specializes in photography, mixed medium custom artwork, and NFT creation.

Join BowTiedPatriot as he dives into making Art in Web3.0 and The Metaverse.

Cooking with BowTiedOctopod

Learn secrets from a fine dining chef for maximum flavor and time-saving efficiency

Newsletters on Ingredients, Techniques and Flavor hacks that will have you eating better. We will never eat bugs!

Meme Warfare with DgenFren

Increase your online engagement, organically influence narratives, and build your online persona by using marketing that your target audience actually wants: memes.

Learn How to Sell with BowTiedSalesGuy

Sales is one of the most transferrable life skills, yet few know how to actually sell.

Traditional sales tactics don’t cut it in today’s hyper competitive world.

Learn the secrets from a Chad Salesman and change your Life forever.

Ecommerce with BowTiedOpossum

Learn the skills to start and build your first online business.

Want to build a business that travels with you?

Learn from an industry veteran that has worked on and with brands you already know.