Skip to content
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

reimplement visibility decorators as functions #10

Open
z80dev opened this issue Jul 27, 2023 · 0 comments
Open

reimplement visibility decorators as functions #10

z80dev opened this issue Jul 27, 2023 · 0 comments

Comments

@z80dev
Copy link
Member

z80dev commented Jul 27, 2023

Currently, defn takes the form of:

(defn <fn-name> <fn-args> [<return-type>] <decorator(s)> &<body>)

Where:

  • fn-args is a list, potentially empty
  • return-type is a single element or tuple literal, and is optional
  • decorator(s) is either a single keyword, or list of keywords
  • body is one or more expressions

Some examples:

(defn __init__ [] :external
    (setv self/greet "Hello World"))

(defn multiply [:uint256 x y] :uint256 [:external :pure]
  (* x y))

(defn addAndSub [:uint256 x y] '(:uint256 :uint256) [:external :pure]
  '((+ x y) (- x y)))

I think having the decorators so far from the function name isn't great. This leads to the first line (declaration line, before the body) to grow pretty long, but breaking it up into multiple lines can get confusing as these elements start to look like they're part of the function body

Some options are implementing decorators as functions

(external 
  (defn __init__ []
    (setv self/greet "Hello World")))

This could in theory allow multiple functions to be defined under the same external block. This might not be a bad pattern, having all the external functions together, but decorators like :view or :pure would still have to go in the defn form, or the nesting will get too ugly

(external 
  (defn __init__ []
    (setv self/greet "Hello World"))
  (defn multiply [:uint256 x y] :uint256 :pure
    (* x y)))

The gains here are not insignificant. we separate the concept of "accessibility decorators" (:external, :internal) from "state modifiers" (:pure, :view). We'll lump in :payable with the "state decorators", mainly because if a function is :payable then it can't be :pure or :view, so we'll never have to have a list of decorators.

Then, we wouldn't really need :internal either if we just set functions to be internal by default (i.e. internal unless explicitly marked external)

New defn specification

A valid defn form would then be:

(defn <fn-name> <fn-args> [<return-type>] [<state-decorator>] &<body>)

  • fn-name, fn-args, and return-type are unchanged
  • `state-decorator is now an optional single keyword, never a list
  • function is internal by default
  • we pass the function definition to external when we want to make the function accessible externally

Implementation as a macro

The coolest thing about this is we can make this change in a backwards-compatible way by just writing an external macro.
This macro does nothing more than take any defn forms passed to it, add an :external decorator according to the current syntax, and output that form.

The road to public

In solidity, a function can be marked public, which makes it accessible both internally and externally.

We can also easily implement public, but not as a macro, because it would require processing code outside of the macro body. But the flow would go like this:

  1. Declare an internal function with the function body and a prepend the name with an underscore
  2. Replace internal invocations of the function with the underscore-prepended invocation
  3. Declare an external function which passes through to the internal function

such that:

(public
  (defn foo [] :uint256 :view
    (+ 3 7)))

(defn internal-user [] :uint256
  (- (self.foo) 2))

is transformed into:

(defn _foo [] :uint256 :view
  (+ 3 7))

(defn internal-user [] :uint256
  (- (self._foo) 2))

(external
  (defn foo [] :uint256 :view
    (self._foo)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant