DEV Community

Kilian Schulte
Kilian Schulte

Posted on

Useless Tips for Dart you probably never need. (Part 2)

There exist a lot of great articles highlighting the most useful tips and tricks for Flutter and Dart. They provide great value for both beginners and advanced developers. 

This article is not one of them.

This is about the useless tips, the weird quirks, the boring facts and not needed tricks. They are either so absurd you won't ever need them, or so abstruse you don't wish to need them. But they deserve some love, too.


Operator overloading

In Part 1 I already introduced you briefly to operator overloading in Dart. And by now you can probably imagine some pretty neat and useful stuff you can do with it. Stuff like vector math, custom maps, … but let's not get distracted. Let's have some fun with it. 

Here are all operators available to overload:
+ - * / ^ % ~/ ~ < <= == >= > & | << >> >>> [] []=

Almost all of them must receive a single parameter of any type and return a value of any type. []= must declare two parameters and return void . == must receive an Object and return a bool.

Actual percentage

Let's start simple. Say you are just learning to code and you come across the % operator. When trying it out, it returns weird results that aren't really what you expected. Now, instead of learning about modulo and becoming a better programmer, let's just fix this obvious mistake:

class RealPercent {
  RealPercent(this.percent);

  final double percent;

  double operator %(double n) {
    return n * this.percent / 100;
  }
}
Enter fullscreen mode Exit fullscreen mode

With this simple class, you can do your percentage calculations as you intend to:

// get 20 percent of 110
var myPercentage = RealPercent(20) % 110;
// myPercentage == 22
Enter fullscreen mode Exit fullscreen mode

DartX

Now, here is a fun one that I absolutely did not spend waaaaay too much time on getting to work. I was asking my flatmate if he had any ideas for use(less)-cases and he was like:

"You can overload < and > right? Why not make HTML in Dart?"

Misusing one programming language to mimic the syntax of another progr a markup language? That sounds reasonable and also very much in the spirit of this article.

Before I besiege you with my struggles, how I got there and how it works, let the following sink in a little:

void main() {
  html <<#p>>'Hello World!'<<#p>>>'' | 'body';
}
Enter fullscreen mode Exit fullscreen mode

This valid dart program will render a paragraph saying "Hello World!" to the body of an empty html page. Can it get any better?

Let's start at the beginning. Before we look at the implementation, we first have to lay out our syntax and define the grammar we use. The first thing you might notice that I am using << and >> instead of < and >. The issue is that Dart does not allow chaining comparison operators in a single expression. Even if we use custom classes and override those operators, something like a < b > c will always make the compiler complain with "A comparison expression can't be an operand of another comparison expression". We could solve this by using parentheses like (a < b) > c, but that's not viable for us since this would break the illusion of writing html. So the next closest thing to use were the bit-shift operators. A nice side-effect is that dart also has the triple >>> operator, which we will use to indicate a closing tag.

So with that our html <p>Hello World!</p> becomes <<p>>Hello World!<<p>>> in Dart.

Next, we have to look at the tags (p) and the content (Hello World!). We obviously cannot just write them out since we still need valid Dart syntax. For the content we can just use a string and wrap this in quotes. For the tag we could do the same, but I think it is nicer and more readable to use the symbol literal (#p). Applied to our example this becomes: <<#p>>'Hello World!'<<#p>>>.

Now, remember that we are still dealing with operators, more specifically binary operators. So we always have to have expressions on either side of an operator. In our case, that is currently not true for the first << and last >>>. In the end we can just append an empty string to make this valid. For the beginning we could do the same, but considering the future implementation, we need an instance of a class that overloads the << operator for anything to actually work. So I decided on using a global html variable, which has the nice side-effect of being explicit about wanting to start some html statement.

Again with all that we look at our current html snippet: html <<#p>>'Hello World!'<<#p>>>''. For clarity let's also realize again that we are actually dealing with normal operators and value literals, we just moved some whitespaces around: html << #p >> 'Hello World!' << #p >>> ''.

Now let's dive into the implementation. I will surely skip some parts to keep it concise, but you can always look up the full implementation on the DartPad I linked below. To figure out our classes and what operators to overload, let's go through our final snipped step by step.

Say the html variable is of class A. A needs then to overload the << operator and accept a Symbol (html << #p). We also need to return a new instance of a new class, since we are in another state of our grammar (inside an open tag); let's call it class B. Class B then needs to overload >> to close the tag, and looking ahead it also needs to overload >>>. Both operators must accept a String for now (b >> 'Hello …'). We can also return an instance of A here, since the next step would again be to open a tag with <<.

What this system also needs to support is nested html tags. Luckily (or by clever design…) our current system already supports that with one slight catch. Because again we are dealing with binary operators, we cannot simply do <<#div>> <<#p>> ... because that would leave >> and << without any value in between. In those cases, we need to insert an empty string between the operators, which works because >> expects a string anyways.

See the full working code on dartpad.dev

There is a lot more that affected the final implementation, like operator precedence and associativity. But I will spare you with any more dry implementation details. Go look it up if you want, or stay for some more amazing features of this new language in a language.

First since we are still in normal Dart, instead of using string literals we can just put in a variable for the contents of a tag:

void main() {
  var title = 'Hello, World!';
  html <<#p>> title <<#p>>>'' | 'body';
}
Enter fullscreen mode Exit fullscreen mode

Second, I took the time to also include attributes in the implementation. You can add attributes to a tag using the [] operator and providing a Map<Symbol, String>. This can again be either a literal or a variable and looks like this:

void main() {
  html <<#p[{ #id:'my_id' }]>> 'Hello World!' <<#p>>>'' | 'body';
}
Enter fullscreen mode Exit fullscreen mode

Third, instead of only accepting Strings as the content of a tag, you can also provide an instance of a previous html statement. This makes this grammar able to handle components much like React:

void main() {
  var component = html <<#p>>'Hello World!<<#p>>>'';
  html <<#div>> component <<#div>>>'' | 'body';
}
Enter fullscreen mode Exit fullscreen mode

Fourth, you can already provide multiple child elements like this:

void main() {
  html <<#div>>''
    <<#p>>'First'<<#p>>>''
    <<#p>>'Second'<<#p>>>''
  <<#div>>>'' | 'body';
}
Enter fullscreen mode Exit fullscreen mode

To step it up even more, additionally to Strings and single components, the final implementation also accepts a List of components. This enables you to dynamically generate child elements:

void main() {
  var items = ['First', 'Second', 'Third'];
  html <<#ul>>[
    for (var i in items) html <<#li>> i <<#li>>>''
  ]<<#ul>>>'' | 'body';
}
Enter fullscreen mode Exit fullscreen mode

Fifth, the resulting element has a render(String target) function, but of course there is also an operator for that: | inspired by the unix pipe operator.


Bringing it all together, let's pause for a second and admire the full beauty and abomination of our creation:

void main() {
  // some inputs
  var title = 'Hello, World!';
  var items = ['First', 'Second', 'Third'];

  var component = html <<#p>>'Let\'s html'<<#p>>>''; 

  // constructs and renders the html  
  html <<#div>>''
    <<#h1[{#id:'title'}]>> title <<#h1>>>
    component
    <<#ul>>[
      for (var i in items) html <<#li>>i<<#li>>>''
    ]<<#ul>>>''
  <<#div>>>'' | 'body';

  /* produced html (formatted):
    <div>
      <h1 id="title">Hello, World!</h1>
      <p>Let's html</p>
      <ul>
        <li>First</li>
        <li>Second</li>
        <li>Third</li>
      </ul>
    </div>
  */
}
Enter fullscreen mode Exit fullscreen mode

See the full working code on dartpad.dev



Do you know any more useless or abstruse tricks? Please leave a comment.

Also I wanted to experiment with something you won't read everyday in contrast to the thousands of 'Tips & Tricks' articles out there. So please show some love in case you liked it or give some feedback.

Top comments (1)

Collapse
 
mvolpato profile image
Michele Volpato

That's wonderful if you are creating a static website generator in Dart.