[MUSIC PLAYING]
GEORGE MOUNT: Hello everyone, I'm
George Mount from the UI Toolkit team,
and I'm here to talk to you about Android Data Binding.
Before we started this I sought some random Android
developer out there for some help in this talk
and I'd like to introduce you to-- I'm
sorry what was your name?
YGIT BOYAR: Random123.
GEORGE MOUNT: Random123, why don't you come up here?
[APPLAUSE]
I stole-- I hope you don't mind, I have some friends in the NSA,
I looked at your laptop and put it up here on the screen.
You guys, don't tell anyone.
YGIT BOYAR: My code.
So, I love Android.
I love that little green robot.
But as a developer, some parts I feel are terrible.
I'm writing so much code, George.
It's like, why is this like this?
Why all this stupid code here?
Why do I need that?
Like this product image: Set that, set this, set this.
Did I study computer science for this?
I don't think so.
GEORGE MOUNT: No.
We've got to have something better than that, right?
YGIT BOYAR: We have something in the box.
GEORGE MOUNT: I do!
Let's talk about Android Data Binding, OK?
All right, let's look at your code in a little bit of detail.
I see this set product UI you are
using calling from onCreate.
That's just a pain, let's get rid of it.
We don't want that.
Instead, let's look at this onCreate.
Let's, instead, just bind your layout to this binding code
and then set the product on there
and let the binding take care of all the work.
Sound good?
A little better?
YGIT BOYAR: Let's see about that.
I'm skeptical.
GEORGE MOUNT: Let's look at your layout.
Wow, you have a lot of ellipses in your layout, man.
What's up with that?
To make sure that we understand that it's a data binding
layout, first we add this layout tag to the outside,
and then we get this variable, the prod variable,
that we set in onCreate.
And then we can use that prod variable
anywhere in our layout.
So instead of this ID we can now access that prod variable.
So, for example, in the source it's an image problem
so we can access it directly.
The product name, it's a string.
And same with the description.
YGIT BOYAR: There is a bug, though.
There you go.
You set a price, it's a crash.
GEORGE MOUNT: Shoot.
All right, well our price is-- if you look at the code there
it's a resource, right?
And our resource is a string and it's doing a format.
We should do better in our expression, right?
YGIT BOYAR: I expect so.
GEORGE MOUNT: I think so.
One good thing is that now we can access our layout--
our expression stuff directly in our layout.
So we can have this access to the string resource
right there, and pass a parameter.
We're passing the product price as a parameter in our resource,
in our layout.
Pretty cool, huh?
YGIT BOYAR: But in my application things
are not always starting, George.
I'm cool with your demo.
But I have this application, sometimes
I have a different layout.
Yes, there you go.
It might be on sale.
How do I do this?
I need to write more code to do this.
GEORGE MOUNT: Whine, whine, whine, whine.
You want everything, don't you?
We allow you, inside your layout,
to have some little dynamism in there.
You can have an expression that says, if you're on sale
then show this on sale sign, and if you're on sale
you might also have a different color for your price.
YGIT BOYAR: Your example is not very realistic because my price
changes, we're a dynamic website.
So I do dynamic pricing.
How you handle that?
GEORGE MOUNT: Well, you have to at least tell us
when it changes.
So let's look at your product.
Your product has a price and name and image.
You have to just extend the base observable class,
and then we mark the things that you
can change that are going to change as bindable.
And then you have to tell us when it changes.
So we have this notify property change and the bindable part--
YGIT BOYAR: But my classes extend the base class.
I can't extend your class, that is not possible.
GEORGE MOUNT: Come on!
All right, all right, fine.
We can use an observable interface instead.
Is that better?
YGIT BOYAR: Maybe, let's see about that.
GEORGE MOUNT: We'll give you a little bit of help here.
We'll give you this property change registry
so you can just tell us when that happens.
YGIT BOYAR: Yeah, that's good enough.
GEORGE MOUNT: That's a little better.
This is a little easier.
It would be nice if we could just have properties
that are themselves observable.
Wouldn't it be?
Here you can access them as if it was just the same
with the same expression.
You just say your prod.image, and even
though it's not a drawable itself we
pretend that it's a drawable.
It's an observable field and it's observable double.
Double for price?
YGIT BOYAR: Did you just double the price?
[LAUGHS]
GEORGE MOUNT: You shouldn't be using doubles for your prices.
Or, if you have more blobby data,
like let's imagine coming from JSON
and you're still doing development,
everything's up in the air, you don't
know what it's going to be like you can use a map.
And that's pretty nice for prototyping.
YGIT BOYAR: Seems interesting.
How about multiple layouts?
GEORGE MOUNT: Multiple layouts?
I guess you have two different variables
and different layouts.
YGIT BOYAR: So I like two activities now?
GEORGE MOUNT: I hope not.
Boy, that would be a pain, wouldn't it?
In one you're setting a product and the other one
you're setting the product list, it's really a pain.
You don't want to have to do if it's
on the left-- landscape do this, and if your portrait do this.
So instead what we do is we merge all of your variables
and we produce one that has the summation of all the variables
that you need, and the binding will just say,
"Oh, I only need these what variables,
and I'll use those in my layout.
The rest of them I'll just not use at all."
You just set it and forget it, it's great.
Just like Ronco, right?
YGIT BOYAR: That seems good.
Talk about the down sides.
GEORGE MOUNT: But wait, there's more.
You don't need to do any more findViewByID() right?
Because now all your expressions are right there
in your layout file.
YGIT BOYAR: Yeah but I run animations
and also put them into the data binding.
It seems weird.
GEORGE MOUNT: Well, OK.
You still don't need findViewByID().
If you have a layout a view with a tag ID in it, then what we do
is we automatically extract that view
and stick it as a public static-- final field
in your binding.
So you can access it directly from binding.
YGIT BOYAR: That sounds good.
GEORGE MOUNT: You really don't need findViewByID() anymore.
YGIT BOYAR: I don't write that code.
GEORGE MOUNT: That stuff is a pain, isn't it?
Also, we have these automatic properties.
For example, here is this DrawerLayout,
and there's this is really nice setter-- setScrimColor.
Wouldn't it be nice to be able to just tag it
so you could just set it right there in your layout file?
There's no attribute for that.
Well, we can just kind of sneak in and say, "Oh, setScrimColor.
That looks a lot like a scrim color, right?
Just to set it right in front of it."
So we just look at it say, "setScrimColor."
Automatically we just say, OK if you
have this thing with a data binding expression in it,
then we will look for the set center with it, that takes
of the same type of parameter.
So in this case the color scrim is an int,
so we say setScrimColor.
We know exactly what it is.
It's just automatic for you, you don't
have to create this new attribute for yourself.
And everyone's favorite on click.
Pretty awesome.
YGIT BOYAR: Infamous.
GEORGE MOUNT: So we have this as well,
we can do onClick with expressions.
Pretty nice.
YGIT BOYAR: How does it work?
GEORGE MOUNT: I think we'll talk about that in a little bit.
We have all the other event handlers too,
like onLongClick or onItems.
Whatever, all those things.
onTextChanged is a real interesting one,
because it's a text watcher and there
are three handlers on there.
You can just set one of them, two of them, three of them.
Whatever you want, it's pretty nice.
How much would you pay?
How much [INAUDIBLE] performance you would pay for this?
20%?
YGIT BOYAR: No, of course not.
GEORGE MOUNT: 10%?
YGIT BOYAR: Uh, maybe.
GEORGE MOUNT: How about nothing?
YGIT BOYAR: Wow, no way.
He's lying.
GEORGE MOUNT: It might not be nothing,
depending on how optimal your code is, but it's pretty good.
I want to bring up my co-conspirator in this.
Let me introduce you to Ygit Boyar.
[APPLAUSE]
YGIT BOYAR: Hey, everybody.
I'm Ygit from the UI Toolkit Team,
I work on data binding with George.
I'm going to go into some details on how it actually
works.
As George showed before the layouts
are a little bit different now.
You have a layout tag in the root.
This tells us it's data binding layout.
And we pass it into the layout grinder,
which processes your layouts, and then explores a new layout
that the older Android versions can understand,
which doesn't add a layout tag anymore,
remove the namespaces to your first child.
And it also has some sub-products
from the processing, it creates a class,
it creates all these public final fields for your views
with IDs, and it creates the setters for your variables.
Going into detail, this is what actually is happening.
We move that namespace to her first child,
get rid of the layout tag.
And this is done while your application
is compiled by Gradle.
And then we remove your expressions add some tag there
so we can find those [INAUDIBLE] afterwards.
If you had an ID we would keep it there, and also
create the vies.
As you can see there directly matching this public file.
You don't need to cast anymore because we know what type it
is at compile time, so we just create the variable
with that type.
So, how do we do this?
One important aspect of data binding
is that almost everything is done at compile time.
So when we see an expression like this we--
while your Java code is being compiled,
we go check, "OK, this product, we
know what type it is because you told us."
Now we say, "OK product is an image field or an image
getter."
We will look for these things.
OK, here we found there is a drawable returning
getImage method.
Then we check, OK, I have a drawable,
there is a source attributes.
Can I set this drawable to the source attribute?
And then we call set source there.
The cool part is, we don't need any reflection
to do any of these things because we do it
at compile time.
So at runtime it is equal to the code
that you would write yourself.
GEORGE MOUNT: Hey wait a second, I thought
all databyte [INAUDIBLE] frameworks needed reflection,
don't they?
YGIT BOYAR: Not the new ones.
GEORGE MOUNT: Not this one?
Oh, nice.
YGIT BOYAR: So for example-- but is not
true that the examples are simple.
So you can say I have my variable, said to this text.
Correct, that's straightforward.
It sets the user of that image.
The source.
I call setSrc which I said before, which does not exist.
So this is a problem because the ImageView
doesn't have a setSrc method.
It has a source attribute, but as a setImageDrawable method,
[INAUDIBLE] you can pass that drawable.
How does data binding know about this?
It's done by annotation.
So we had this binding method annotation which-- you can say,
OK, this is a binding annotation for a type class ImageView
that attribute a source and the method is
called setImageDrawable.
So we know that at the resource maps are setImageDrawable,
if the pass parameters match we can use that method
to run the binding.
Again, this is done in the compile time.
What we generate is the same code
that you will do at setImageDrawable.
[INAUDIBLE] event handler.
These are a little tricky because unfortunately Java 7
didn't have any function parameters, you cannot do them.
So the way this works is, we know
there's a binding method that says onClick.
Method setOnClickListner.
OK, what does the setOnClickListener expect?
It expects a [INAUDIBLE] .onClickListener
that's an interface or [INAUDIBLE] and then
the interface has one method.
Now if you look for that handler.clicked
matches that one method.
Going into the details, we saw this.
Nice, that the handler.clicked method receives a view
and this matches so we create the interface for you
so that Java is happy, and you're going to tunnel
those calls to our handler.
So you can see everything is matching.
It just works.
GEORGE MOUNT: You're stealing my thunder here.
Let's talk about binding adapters.
Binding adapters are probably the coolest part
about data binding.
So let's talk about something a little bit
more complicated than setText.
SetText was a nice automatic variable.
You can just setText, it takes in a string--
or, actually to setText takes in an char sequence
but it's pretty close.
Let's talk about something more interesting.
We have this ImageView but we have a large URL,
large image data coming down.
And if we do this, what's going to happen--
we don't want this on the UI thread.
It's going to load everything on the UI thread.
That that's pretty lousy, I don't like that.
So instead, I'm going to use a tool.
How about Picasso?
Glyde?
What's your favorite?
YGIT BOYAR: I'd rather not say that.
GEORGE MOUNT: In this example whoever
it was who wrote this expression tried to use Picasso,
but my goodness, Picasso with context-- that's
a heck of an expression, and into what do you--
I don't know.
That's lousy.
I don't like this.
We don't want to see that in our expressions anyway.
So let's do something else simpler.
Instead, what we're going to do is create a binding adapter
and we're going to use the Android source.
We're going to override what the default behavior is
with our binding adapter.
And instead of doing the normal stuff
we're going to try to do something special.
So what we're going to do is set this binding adapter,
and of course this is an attribute, an annotation
on our static method here.
And it could be any static method anywhere.
And we're just going to look for that static method
with the attribute, the annotation.
And here we're going to look for something that is an ImageView
and it takes in a string as a parameter.
And now what we can do is do anything we want in that class.
So we have this nice Picasso.
We can use their context from the view.
We can load the image in there, and it
can be done all off the UI thread,
and it's all kind of magic.
Now you can do image source is equal to some value,
it's great.
But what if you want to do something more interesting.
Let's imagine you want to have a placeholder
for your annotation.
Now you have to do this with Picasso in the same call,
you can't just say, "in one call it's
called the load in the other one you do--"
so what we're going to do is we're
going to merge it all together into one binding adapter.
This one takes two kinds of attributes,
and they can work together.
You just take the parameters in the order
that you've assigned them in the annotation,
and now you can do whatever you want in the method.
In this case we're going to load the URL off-thread,
and in the meantime we'll load this placeholder image.
[APPLAUSE]
Now sometimes you want to have some kind of instance
information in your adapter.
And before we were using static methods.
But what happens if you want to use an instance?
With the static method it's easy.
We know what to do.
We can call it directly just my class static method call.
Very simple to do in the generated binding class
that we have.
YGIT BOYAR: How do you get the instance?
GEORGE MOUNT: So we take out the static what happens?
Where does that instance come from?
Some kind of instance.
So what we're going to do is-- the binding framework
is going to look and see, "Oh, this is an instance binding
adapter.
We need to generate this method on this class, this data
binding component class."
And this method is going to be called
get whatever the name of your adapter class is.
And now it's your job to implement
to implement this class.
So you've been with this class, and then you
call setDefaultComponent on it.
Now, there's also ones if you want
to load a specific implementation
for a specific binding if you want.
But most of the time you probably
want just the default component that you're going to load.
Then we know exactly what instance
we're going to load for your binding adapter.
Very nice.
Now you can also do this with components.
Now when you're doing it with a component
if you have some kind of state you want to get.
Imagine this is a cache for your images, right?
So you want to load the image from your cache first, and then
possibly load off-thread.
In this case we need to go what that instance is.
Where we're going to pass it as a static method,
but we want to have some kind of instance
that we're going to share around to all
the different binding adapters.
So in this case we need to know what that state is.
So in this case you implement your data binding component
but you add your own method to it.
OK?
So when you had your own method to it,
we don't know anything about this method,
this is something that you know about.
But we're going to pass it to you as the first parameter,
if you'd like.
Now, you can do whatever you want.
So we have our own cache here that we can load our data from.
Let's talk a little bit about best practices.
YGIT BOYAR: Let's go through some examples.
GEORGE MOUNT: They say practice makes perfect.
YGIT BOYAR: Practice.
GEORGE MOUNT: Practice, man.
YGIT BOYAR: [LAUGHS] Internal joke, sorry.
Let's look at some examples.
Data binding allows you to write some explorations in the XML.
That means I can just send a web service call from my XML,
right?
Why not?
There's a click listener.
There's an API.
Why should I not do this?
You should not do this.
If you do this, your application will break.
This is not what data binding is for.
Data binding and is to put data into your UI from your model.
So instead of doing that, have a call
back, have a presenter, whatever model you prefer.
Just [INAUDIBLE] the call to the Java
when you do the real thing.
Don't try to do business logic tree here or something.
Its not going to work.
Another example in a good way is that, I
want to change this drawable based on the users [INAUDIBLE]
just reacted.
In that case it's fine.
Just what the eye sees is a super simple expression.
That's OK, because here's an advantage, when I look at this
here it's OK, I know that if the age is this UI
shows this drawable.
Otherwise the other one is very clear,
it makes my example better, my code cleaner.
So this is OK.
So you have to decide it for yourself.
Well, if you do something like this, [INAUDIBLE] redact it.
I don't understand what this code is doing when I look
at it, then there's a problem.
It doesn't make sense.
Instead of doing it, there's something simpler.
If the age is this, the displayName otherwise redacted.
And the displayName comes from your model.
If your object doesn't really have that field, which
it doesn't in this case, you create a view model
that provides that information, or you
can make the variable for your binding layout.
GEORGE MOUNT: I think you took that from my code, I'm sorry.
YGIT BOYAR: It's not very good.
He got data binding wrong.
GEORGE MOUNT: Hey!
YGIT BOYAR: So if your real model
can display [INAUDIBLE] in this example
we make this displayName bindable.
In return, data binding is going to generate this BR clause
similar to the R clause, but for bindable things.
And when the user's last name is set you can [INAUDIBLE]
that it has changed and data binding
will keep the UI up to date.
If you have value objects and you're directly showing them
in your UI, that's okay to set them
as variables in your layout, and set [INAUDIBLE]
your generated binding class.
But if this is not the case, if you need more information
consider using a view model where you put this information
there, and you can just use these observable convenience
fields we provide your view models.
You just set them and data binding
makes sure of that they are visible on the UI.
By the way, observables like those convenience
observable classes we provide, they're
nice if there are very few.
If you tried to make your value objects with those things
you're just using a lot of my memory for no reason.
Don't do that.
But they're nice if you have a view model
or you could have them in your activity
if there's something you want to easily control.
So there's other examples where you
write the view model extending the base observable
class because you don't want to use those convenient classes.
The same example here, when you the data changes you notify,
and then data binding takes care of this.
Or you can implement observable interface,
now we provide this program to change
registry class which allows you to dispatch your [INAUDIBLE].
All they have to do is, just notify PropertyChange
through that class.
And when we add and remove callbacks,
just send those calls to this class
and it will take care of it.
The other part is-- This is a beautiful example.
I know many people have been asking for this font editor
within TextView.
There's some reasons for that.
You ask the [INAUDIBLE].
Lisa, I don't know if she's here,
she's created this thing where I can set my fonts in XML.
I want to do that, it is much cleaner.
This became very popular, I like this example.
The good thing about this example
is it makes your XML very clean.
You look at it, you understand what it is trying to do.
There's no added performance cost in all of these things.
So you write the binding adapter that says,
I know how to set a font on a textView.
This is all well defined.
In this code you get the font.
You load the typeface.
Set it on the text view.
If this was a real application you
would probably cache it so you don't keep reloading the font.
Beautiful.
Another good example is the image adapter.
I'm using any image loader here, Glide.
I could say, this adapter knows how to set a photo URL
and might have a default but they're not required.
So that if there is only a photo URL set on the view
we will still call the adapter the other value you will see
will be the default value, which is if it is an object
it will be null.
So an integer will be zero and all the default
values you can imagine.
This way I can write just one adapter
that can handle multiple attribute groups.
And if it is an instance method you
can just create this AppComponent
that implants the DataBindingComponent
and just returns your image adapter.
This is very nice for testing so that while the test is running
you can basically set the default, or do nothing,
because no one wants to call network during a test
unless you are testing the network.
So I have this mock version here that I inject during my test.
And it just does nothing.
It uses the default drawable.
So this works one-on-one with [INAUDIBLE].
You can just say inject ImageAdapter, create this app
component and for example, if you are using Dagger 2
this will take care of the rest.
You don't need to the anything else
and this is a Dagger 2 implementation where we always
say-- We create the model for the stuff,
and we implement this, and then Dagger
generates the rest of the code assuming that you provided it.
And thank you.
[APPLAUSE]
GEORGE MOUNT: We were super fast so we have
time for lots of questions!
YGIT BOYAR: There are two microphones left and right.
Please use them to ask questions.
AUDIENCE: Hi, my question is about when you use data binding
it's not always obvious what's happening in the UX editor.
If you understand what I mean.
It would be nice to be able to provide a default
product, or something to mock so I can see what a UX looks
like in the editor as well.
GEORGE MOUNT: Yeah, that was one of the first things
that we talked about when we were talking to the Android
Studio team.
And they were really excited about data binding
but as you saw in the last talk, they
are working on some pretty exciting things right now.
And so they're going to get to it but they're not there yet.
YGIT BOYAR: I can tell that code completion is
coming this way of course.
That's good news for data binding.
And that's one of the things we should do.
AUDIENCE: Is it possible to inflate ViewStub
according to data binding?
GEORGE MOUNT: You said, "Inflate new stuff"?
AUDIENCE: ViewStub.
GEORGE MOUNT: Oh yes, there's a special implementation
for ViewStub because as you saw we have final classes--
final fields.
So we have a ViewStub proxy final field for that.
Because ViewStub actually replaces itself with a view.
So we can't do a replacement for a final field, right?
So we have a ViewStub proxy and you
can get either the view, or the replaced view with it
depending on its status.
AUDIENCE: OK, and it is possible to parse the data model
to underlying [INAUDIBLE].
YGIT BOYAR: Yes, you us the same expression
as if you are passing an attribute.
And if there's a binding for that class
we know to create the binding for that class
and pass that variable as the variable changes.
AUDIENCE: Cool, thank you.
AUDIENCE: Hello, the current design tab
inside Android Studio sometimes doesn't render the layout
correctly.
Sometimes there is just a black screen or something like this.
Are you going to improve this and will its work with data
binding also?
GEORGE MOUNT: So we are constantly
improving the Android Studio layout editor.
So that's going to get better and better over time,
absolutely.
AUDIENCE: OK, thank you.
AUDIENCE: I was wondering, you showed the image
loading examples.
How would you go about canceling the loads when
your UI is torn down somewhere.
YGIT BOYAR: You have the binding so you can model it--
so for example you create the binding--
what you are trying to cancel is--
let's say you are trying to load user image URL,
and then the image URL disappeared or--
AUDIENCE: No, I mean like in Picasso, you can pass a tag
and then cancel every loads on those tags for example,
when your fragment goes away, or something like that.
YGIT BOYAR: One option would be passing that tag as well
to the binding adapter.
Now you can cancel through Picasso.
Or if there's some variable in your model
that can control that then, again, the binding adapter
can handle the canceling.
AUDIENCE: OK, but it's not really a callback
for tearing down--
YGIT BOYAR: You can pass a callback variable if want.
For the view tearing down-- You know
when the view is going away through the Android view life
cycle, and there are callback methods
that you can assign to this binding class.
You can even say, "Hey stop, don't rebind."
The mandated changes generated by the binding class
calls your callback, "I'm about to re-bind."
And now you can say, "No.
Stop.
Don't re-bind."
When you say that you are responsible to tell it
to re-bind whenever you want.
Which is very useful if you are using inside the RecyclerVIew.
Recycler gets really upset if you update the views themselves
directly.
So if you're at the RecyclerView.Adapter you say,
"Don't change. " And in runs it through the RevyclerlViews like
item change flaw.
AUDIENCE: OK, I think that answers my questions.
AUDIENCE: What's the best way to debug the expressions that
are in the view markup?
Because it's logic effectively and so if there's a bug
how do you debug it.
How do you step through it?
YGIT BOYAR: Well, you can't step through the code, the source
code that we generate is actually visible to you.
It's generated and you can step through it if you need to.
It's a little bit on the uglier side
because it's generated code, but you can't step through it.
You should try to limit what your expressions look like.
Now we have some things that make it a lot easier for you
so that you have fewer bugs.
For example, we have a no coalescent operator
which-- those of you who have used other languages
know what this is, but essentially-- says
if the first part is null then use the second part.
And we also automatically do null checks
on your expressions.
So if any part of it is null then the resultant value
is a default value.
So if you call setText on user.name then,
if user is null, then the whole expression is null.
You'll see fewer bugs from that.
Like in the best practices you should limit your expressions
so they're not too complicated.
AUDIENCE: Yeah, I would agree.
Thanks.
AUDIENCE: Hello.
When we're using data binding with recycle views actually,
the documentation says that we should--
after passing the view to the view holder
and get the binding clause.
We should use as a executePendingBindings.
I want to know exactly what is it like,
because I'll tried to use on list view
and didn't call that method and it worked fine.
YGIT BOYAR: It will work fine but it will-- As the variables
change we don't instantly go and update the views.
What data binding does is we just keep track
and wait until the next animation frame happens.
This helps us to run less explorations
because it's more efficient.
Plus you can change your data on any thread.
You don't need to be on the main thread
while changing your data, and data binding
will take care of moving it to the main thread.
Now the way this works is you wait until the next animation
frame.
From a recycler perspective for the list view, what it does
is it calls your own bind method and it
expects the view to be updated when that method returns.
So if there's any TextView that you
should set that takes when that happens,
otherwise the view won't be measured properly.
The first layout will be wrong.
The next animation frame, data binding will update that view.
This is going to cause another layout which
will correct itself.
It looked like it worked fine, but it actually
did two layouts for no reason.
So you by calling executePendingBindings,
you sync all the VFs with your model
so that data binding is not going to request another layout
and the ListView or RecyclerView will run the proper layout
calculations.
AUDIENCE: So, the last one.
When you're importing variables such as Android-- the base
class to use an expression-- I want
to know if on the new Android Studio
we actually have error fix because if you
try to do that expression of setting visibility,
it actually shows you an error, even after compiling.
So I want to know if that's fixed on Android Studios?
GEORGE MOUNT: You said for compiling?
I shouldn't show you errors for compiling.
YGIT BOYAR: It does show an error.
It's a very detailed problem.
While parsing your expressions we use ANTLR.
We say grammer parser is very popular.
That model doesn't work on IntelliJ.
IntelliJ suggests using another parser called JFlex.
So sometimes these grammars don't match properly.
So if you have a bug just report it and we will try to fix it.
We are working on some other solutions that
will allow us to use ANTLR parser inside IntelliJ
but there are fundamental different models,
so it's not very [INAUDIBLE], but we are working
on making it more reliable.
GEORGE MOUNT: All right, thank you.
[APPLAUSE]
[MUSIC PLAYING]