On Mon, Aug 24, 2015 at 11:12 PM, 'Bob Nystrom' via Dart Misc <
Post by 'Bob Nystrom' via Dart MiscLong reply is long!
*Theoretical consistency*
I like the proposal in principle. The fact that a semi-arbitrary set of
methods/functions is hardcoded in the language as "these are const and
nothing else is" has always felt magical and special case-y. Also, any time
users can write an expression, they almost always want to be able to create
their own abstractions so they don't have to copy/paste the same expression
over and over again. const expressions have always been a sort of unloved
step-child to normal expressions in Dart.
I agree, and I would like const functions.
That said, the current hardwired functions are almost exclusively ones that
could not be expressed with the proposed const function syntax. They all do
meaningful computation (e.g., arithmetic or toString).
A const function would only be able to do what a potential compile-time
constant expression can do, like the ones we have in initializer lists. One
of the use cases I can see is exactly moving such code out of initializer
lists.
Post by 'Bob Nystrom' via Dart Misc*Pragmatic usefulness*
Having said that: in practice, I don't think const has proven to be that
useful in Dart. Angular is very metadata and metaprogramming heavy, so it's
a bit of an outlier, but in a lot of Dart code I read, const is rarely
used. I've seen a number of classes start out with const constructors and
then end up becoming non-const over time because the limitations are too
onerous. When that happens, honestly, not much is lost. It's not like using
const gives you that much benefit in Dart.
Given how much complexity they add to the language, I don't feel they've
ever really carried their weight. I could be wrong, but my intuition is
that a lack of const functions/methods isn't what's holding them back. The
main problem is they just *don't do much*.
True. The guaranteed canonicalization is the only real advantage. Apart
from that, generating the object at compile time would be just a compiler
optimization.
I still like the concept, and think it actually works very, even if it
doesn't do *much*.
Post by 'Bob Nystrom' via Dart Misc1. *To possibly enable some VM optimizations.* Since you know a const
expression's result will never change, the VM could cache it. For example,
for (var i = 0; i < 9999999; i++) {
var c = const SomeSlowToCreateClass(...);
}
It's safe to hoist that const constructor out of the loop since it
will never change. Maybe I'm wrong, but I believe smart VMs can and do do
that for regular non-const classes automatically anyway, so I don't find it
very compelling to add a whole shadow "const" sublanguage just to enable
that. Even if the VM can't optimize this, you know, just hoist it yourself.
There are few slow-to-create const classes because of the restrictions on
const constructors.
Where I see this used is mainly on tables (lists or maps) where you can
inline a const table without creating it every time the function is called.
That is, function hoisting rather than loop hoisting.
Post by 'Bob Nystrom' via Dart Misc1.
2. *To have some values that are reliably computable at "compile
time".* This is your use case, because metadata annotations require
this. That way, the values of the parameters to a metadata annotation can
be computed at "compile time."
It's also used for the default values of parameters, which I think is a
more common use (even if we tend to use null as default and replace it with
the actual default value using code).
Post by 'Bob Nystrom' via Dart Misc1.
I would find this more compelling if "compile-time" really meant
something in Dart, but it doesn't right now. We *are* statically
compiled, with dart2js, but it doesn't use annotations for much. We don't
have any real static metaprogramming story unlike, say, D or C++. Our
runtime reflection story doesn't play nice with the dominant way that Dart
is executed in the wild (compiled to JS).
This puts us in a weird position where annotations are sort of
"write-only". You can put them in your code, but it's actually really hard
to do anything useful with them. (And I would put transformers in the
"really hard" category.) Given that, I find it hard to get excited about
making const expressions more expressive without a plan to actually make
const expressions more *useful* to begin with.
For what it's worth, C#'s attributes have always had similar limitations
in the kind of parameters you can passâbasically just literal valuesâand it
hasn't caused too many problems.
If you find yourself stuff so much code into metadata annotations that you
find yourself wanting the full expressiveness of the language, to me that
feels like it's going against the grain of the language. Is there a way to
design your API such that that code is just *code*?
For example, the unittest (now just "test") API maybe could have used
@Test("you can add numbers")
testAddition() {
expect(1 + 2, equals(3));
}
But I put that stuff deliberately as normal parameters in imperative code
because it's more expressive than limiting the user to the half-language of
const expressions.
*Compile time or not, there is no try*
My general feeling is Dart needs to either have a real compile-time
metaprogramming story or not. If it does get oneâsomething like macros,
templates, etc.âthen, hell yes, we should have constant functions. We need
to make the compile-time language as complete as possible.
If it doesn'tâand right now we don't have any concrete plans to give it
oneâthen making const expressions incrementally more expressive without
coming up with new ways to do useful things with constant values doesn't
really help users very much.
*Comments*
For example, this proposal does not include: ... lazy evaluation
For what it's worth, lazy evaluation doesn't need to be mentioned. Since
const expressions are pure, it's not visible to a user whether evaluate is
lazy, eager, by name, whatever.
const expressions can be syntactically and lexically transformed to the
existing syntax that is accepted by current Dart implementations. Anything
that requires more than static transformation is beyond the scope of this
proposal.
Doing this correctly requires more than a simple textual substitution. The
namespace of the code where a const function is declared may be different
// fn.dart
const name = "I'm from fn.dart";
const fn() => name;
// main.dart
import 'fn.dart';
const name = "Oops, I'm from main.dart";
@SomeAnnotation(fn())
main() { ... }
If you just expand the fn() invocation to its body, it's not going to do
the right thing. Scope is hard. Of course, this can be implemented
correctly, but doing so starts to look a lot more like a little term
rewriting language interpreter than like the simple text preprocessor
you're going for.
True, you can't just move the const expression - it might depend on private
const variables from its original scope, nothing will make that work.
However, it's just a matter of how deeply you need to expand the const
expression before all the variables are either basic values or visible from
where it's expanded.
Worst case, it will expand to a complete const expression with no variables.
Internally in a compiler, scope should not be a problem, you can probably
just refer to the const value.
Post by 'Bob Nystrom' via Dart Misc---
You don't specify this, but your semantics require that const functions
and methods cannot be recursive or mutually recursive. Otherwise, the
expansion doesn't terminate.
It is important to avoid having more than a finite number of compile-time
constants (and preferably at most linear in the actual source code size),
so any recursion of a const function should be prohibited.
Currently we avoid arbitrarily recursive const constructors because the
arguments to a const constructor call in an initializer list must be
compile-time constants, not just potential compile-time constants, so any
call will have a value fixed value by the call site, and therefore any
recursive call will diverge.
(Well, and because we just prohibit it in the VM, dart2js gets a stack
overflow).
Post by 'Bob Nystrom' via Dart MiscIf we add constant functions, I think users will almost immediately want
some kind of flow control, at least branching. Think how nice it would be
to have a const function that allows a single argument or a list of them
and can handle both cases appropriately.
Using ?: is already a compile time constant if the operands are, so we have
that. What we might want is a compile-time constant "is" check.
Post by 'Bob Nystrom' via Dart MiscAt that point, recursion *could* be allowed as long as there was a
reliable base case. But now you're inching towards Turing-completness and
all of the scariness that causes in code that runs at
compile/static-analysis time.
Yes, let's not go down that road. It does matter that it's undecidable,
even if there are efficient algorithms.
Post by 'Bob Nystrom' via Dart Misc---
I agree that if you're going to have const functions, you should have
const methods too since Dart is so method-oriented. Also, doing so would
give a coherent way to explain why "1 + 2" is a valid const expression. I
do worry that somehow dynamic dispatch may sneak in. I can't think of any
good examples, so maybe not.
It shouldn't - const methods will only make sense on const objects, so it's
the actual method on that object that needs to be const, and if it is, you
are fine.
We do need to consider whether overriding a non-const method with a const
method (or vice versa) is a warning or error. It might not need to be.
We probably also want to allow access to final fields on const objects.
That breaks the field/getter symmetry, so we might want to define const
instance fields (the ones you are allowed to read at compile-time) vs
non-const (just plain final) fields. That way, you can see that changing a
const instance field to a non-const getter will break code. If a field is
just final, you keep the option of making it a non-const getter later.
Post by 'Bob Nystrom' via Dart MiscAs always, this is just my gut feeling. I definitely don't speak for the
entire team.
I like this, but you are probably right that it's not a big gain.
It *is* doable as a preprocessor.
I should write a preprocessor [img: procrastinator cat].
/L
Post by 'Bob Nystrom' via Dart MiscCheers!
- bob
On Mon, Aug 24, 2015 at 12:03 PM, 'Natalie Weizenbaum' via Dart Misc <
If both const functions and const methods must be preceded with the const
keyword, wouldn't your example have to be written as const (const
bind(String)).toValue('hello, world!')?
On Sat, Aug 22, 2015 at 5:03 PM, Anders Holmgren <
Post by Anders Holmgren+1 for this being a cool idea.
Be very useful for some of my packages that use annotations like
constrain and shelf_rest
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to
http://www.dartbug.com/new
To unsubscribe from this group and stop receiving emails from it, send
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to http://www.dartbug.com/new
To unsubscribe from this group and stop receiving emails from it, send an
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to http://www.dartbug.com/new
To unsubscribe from this group and stop receiving emails from it, send an
--
Lasse R.H. Nielsen - ***@google.com
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 KÞbenhavn K
- Denmark - CVR nr. 28 86 69 84
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to http://www.dartbug.com/new
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.