-
-
Notifications
You must be signed in to change notification settings - Fork 42
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
HTML templating style/API: varargs instead of do blocks? #7
Comments
Now for creating components you can use the functions with signatures:
The main advantage for me is a clear separation of the element body from its parameters and getting rid of the hell of nested brackets. But this is my personal opinion. About deprecate/remove it. If the Plotly team decides so, I will do it. But for me personally, this will mean extreme inconvenience in using such a package. |
Fair enough — this is a matter of syntax preference and so is quite subjective. |
Overload is a wonderful mechanism and one of Julia's great advantages. So I don't really understand the suggestions to remove the signature in favor of "perhaps more convenient" if we can leave both and offer the user to decide on the situation. For example, for a large block, "do" may be convenient, and for small sub-blocks inside it, the option with brackets may be convenient |
It really only becomes more important for pedagogical reasons — I think it's helpful to have an opinionated standard style to promote readability and ease-of-use. |
Re Do
The ability to put short keyword arguments in the front of the declaration is very important. The use case is for when the declarations become very long and it becomes tricky to know which keyword arguments match up with which components. On the Python side, we'll frequently have code that starts out looking like this where html.Div([
html.Div([
# ...
]),
# ...
html.Div([
html.Div([
# ...
# ...
# This could be like 100 lines
# ...
])
]),
]) and then, once more keywords are added to some of the components, morphed into this: html.Div([
html.Div([
# ...
]),
# ...
html.Div(
id='my-parent-div',
style={'color': 'blue'},
children=[
html.Div(
id='my-child-div',
style={'color': 'red'},
children=[
# ...
# ...
# This could be like 100 lines
# ...
]
)
]
)
]) Without the ability to put other keyword arguments up front, this code would look like this, where it becomes very difficult to see which keyword arguments apply to which components. Whenever children becomes more than e.g. 10 lines of code, we recommend that folks move their arguments up front. html.Div([
html.Div([
# ...
]),
# ...
html.Div([
html.Div([
# ...
# ...
# This could be like 100 lines
# ...
], id='my-child-div', style={'color': 'red'})
# ...
# There could be another set of components in here
# that could be another 100 lines...
# ...
], id='my-parent-div', style={'color': 'blue'}),
]) |
(In Python, we don't have the luxury of being able to have an arbitrary positional arguments after keyword arguments: |
Another thing to consider is how easy it is for a user to assign children as a variable and pass it in. For example, how easy is it for a user to unpack html.Div([
html.Div(id='1'),
html.Div(id='2'),
html.Div(id='3'),
], id='parent') into my_children = [
html.Div(id='1'),
html.Div(id='2'),
html.Div(id='3'),
]
html.Div(my_children, id='parent') In Python, if we had Instead of html.Div(*my_children) Unpacking arguments with Another note about our decision in Python to use explicit lists. In callbacks, users should be able to update their components's properties using the same data structure as they might use in So, if we have: my_children = [
html.Div(id='1'),
html.Div(id='2'),
html.Div(id='3'),
]
app.layout = html.Div(my_children, id='parent') then in a callback, this could be updated with: app.layout = html.Div(id='my-parent')
@app.callback(Output('my-parent', 'children'), [...])
def update_parent(...):
return [
html.Div(id='1'),
html.Div(id='2'),
html.Div(id='3'),
] If we accepted positional arguments as children, then there could be some asymmetry with what is supplied directly as a component property vs how to update that component property with a callback. By assymetry, I mean:
vs app.layout = html.Div(id='my-parent')
@app.callback(Output('my-parent', 'children'), [...])
def update_parent(...):
return [ # <-- Asymmetry here! Where did this list come from? We didn't need it in our layout
html.Div(id='1'),
html.Div(id='2'),
html.Div(id='3'),
] (The Another comment with
whereas in JSX/HTML/XML, it looks like:
of course frequently it just looks like this:
which isn't that much more helpful 😸 |
This work now:
In Julia, an argument can't be both positional and named. In terms of the function signature, this looks like
|
I've really been enjoying Dashboards.jl — and am thrilled to see this becoming Dash.jl! I've been brainstorming a bit on how to make the HTML templating a bit simpler (and closer to both HTML & Julia syntaxes). One thought I've had is to de-emphasize (or maybe even deprecate/remove) the
do
block form and instead allow passing children as varargs to the components. Since we can pass keyword arguments before positional arguments, we can still have a decent structure.As an example, DashboardsExamples/dash_tutorial/5_interactive_graphing_1.jl becomes:
The biggest advantage over the
do
block form is that it's easier to catch mistakes. Forgetting a comma at the end of a line in ado
block just simply ignores everything that precedes it! It's an error like this. I also think this matches Julia's style a bit closer while still allowing you to putid
s andclass
es right up front (like in HTML).The text was updated successfully, but these errors were encountered: