Log of the #nice channel on irc.freenode.net

Using timezone: Central European Time
* arjanb leaves04:09
* bonniot joins08:38
* arjanb joins11:16
<bonniot>could you write some testcases to show which situations you plan to handle?11:39
<arjanb>should i commit these to cvs?11:43
<bonniot>you could, with a bug marker11:44
but you can paste them here first
<arjanb>?String s = maybeString();11:49
if (s == null)
s = "xyz";
<arjanb>?String s = maybeString();
?String t = null;
if (s != null)
t = s;
<bonniot>ok, wait11:52
in the second one, what is needed is to take assignments into account, right?
<arjanb>it should take always assignment in account even if the assigning variable has an conditional type11:55
?String s = maybeString();11:56
if (s != null)
void foo() { s = null; }
<bonniot>you mean if it's captured?11:57
<arjanb>yes it shouldn't behave like captured before the closure is declared11:58
* CIA-3 leaves11:59
<bonniot>ok, but it looks to me like an unrelated issue
* CIA-7 joins12:00
<arjanb>it is but this testcase fails currently
<bonniot>ok, i understand that
i just would like to consider the situations one by one12:01
i want to see how hard it would be to keep the current system12:02
for the 2 case, it should be rather easy to handle assignments, it's similar to 'assert t instanceof String' (since s has type String at that point
existing loop testcase:
./// FAIL bug
?String s = "xyz";
String t = "abc";
int x = 0;
if ( s != null)
do {
t = s;12:04
s = null;
} while(x++ < 10);
* CIA-7 leaves
<bonniot>the 'assert ... instanceof ' was implemented in 3 lines of code, so assignments should be easy :-)
* CIA-2 joins
<bonniot>for the first case, there could be something in "exitBlock" that merges the types from the different branches, and keep the smallest common type12:05
<arjanb>String s = maybeStringGenerator();12:07
while (s != null) {
s = maybeStringGenerator();
<bonniot>?String s ...12:08
<bonniot>is this one not handled currently?12:10
<arjanb>this one should still work when the above testcase don't typecheck12:12
for loops, doesn't it need a fixpoint computation?12:14
<bonniot>in general, a fixpoint of a function f is a value x such that f(x) = x12:16
<arjanb>typecheck(Loop l)12:17
do {
} while(l.loopentryvariables.any(haschangedtype))
<bonniot>yes, that's it12:18
did you find an article about this problem?
do you know any articles about that?12:20
not precisely, but I think it's known as dataflow analysis
anyway, I think you found the right algorithm ;-)
<arjanb>?String s = "abc";12:23
do {
s = maybeStringGenerator();
} while (s == null);
this does fail atm12:25
<bonniot>yes, the loop condition is not used atm12:29
note that you can only use it of there is no break statement inside
<arjanb>that is why i want to transform the ast in ssi form12:33
<bonniot>i don't see why it's needed12:34
<arjanb>?String s = "abc";12:38
int x = 0;
do {
s = "xyz";
if (x > 10)
s = maybeStringGenerator();
} while (s == null);
why is ssi needed?12:40
<arjanb>it's not needed but it makes typechecking phase a lot easier
<bonniot>that's not clear to me. you would need to write the whole ast->ssi conversion in addition to typechecking itself12:42
then it would be less efficient, because you would creating lots of new objects
i think the current system already takes care of assignments to variables on which you have more precise information12:43
it just needs to be used in the remaining cases
see how assert .. instanceof was done in a few lines12:44
<arjanb>assignment can be done that way but adding merging of branches would be more difficult12:49
<bonniot>no, you just check the values on the top of the stack12:51
<arjanb>and if there are more than 2 branches?12:52
<bonniot>you do it incrementally12:53
at the end of branch 1, you remember the type
at the end of two and later, you take the max of the stack type and the current type12:54
<arjanb>i don't think that can work in all cases12:58
the stack way can only merges branches at the same level12:59
<bonniot>oh, you meant nested branches?13:00
(I was wondering, because there are never more than two branches at the moment, but I thought you considered 'switch')
with nested branches, you do nothing special. the stack will grow at each nesting, and when you leave a branch you merge the types at the level13:01
the same way it is done now
with merging at the end of each branch13:02
<arjanb>?String s = "abc";13:04
outer: do {
int x = 0;
while( x < 10) {
s = maybeStringGenerator();
if (s != null)
break outer;
s = maybeStringGenerator();
} while (s == null);
<bonniot>where's the problem?13:07
<arjanb>how would that work with a stack merging the break with the outer loop exitbranch?13:08
<bonniot>ok, when you reach the break, you need to access the location where exit types are stored. that can be done by storing that info in the Loop object13:11
<arjanb>i'm wondering what other special cases are need with a stack13:14
<bonniot>how would it be simpler with ssi?13:16
<arjanb>then you a few operations at typechecking with a straight forward implementation13:20
<bonniot>but you can you exactly the same algorithm without ssi, once you have the utilities to manipulate the set of types of variables, which are already mostly written13:25
basically, it's a different representation for the same idea. only it's more efficient and already there13:26
<arjanb>if i had too much i would try to implement both and compare13:29
?Collection<int> c = null;13:30
c = new ArrayList();
void foo() { c = new HashSet(); }
<bonniot>ready to commit your testcases?14:21
<arjanb>i have to think about a few more testcase14:24
<arjanb>why does assert only work for instanceof?14:25
<bonniot>what else?14:38
!= null ?
<bonniot>true, it should handle that too
<arjanb>?String s = "abc";14:44
?String t = "xyz";
println(t.substring()); //pass
void foo() { t=s; s = null; }
println(t.substring()); //fail
multiple passes can be needed for closures14:47
?String s = "abc";14:50
void foo() { s = "xyz; }
<bonniot>i don't think we should even try to handle that case (the first case)
total inference is undecidable anyway14:51
<arjanb>how would it be undecidable?14:52
i think checking a closure multiple times is unavoidable in some cases14:56
?String s = "abc";15:08
s.substring(); //pass
void foo() { s./*fail*/substring(); }
s = null
<bonniot>it's undecidable because you can't predict at compile time how the program will behave at runtime15:10
for instance, in your first case, it matters that foo is called twice15:11
but if it was called twice inside a loop, you won't know it statically
so you always need to make approximations
and the point is to focus on common enough and simple enough cases15:12
<arjanb>is it's inpossible to determine how many times it's called so you need to assume infinite times15:14
for closures it's finding the fixpoint of the captured variables15:18
<bonniot>i think in practice you almost never know how many times a closure is called, so this case is not important15:23
<arjanb>it is because a checking a single time isn't enough in the second last case15:26
<bonniot>that case is unrealistic15:28
<arjanb>the last example is15:29
<arjanb>is not i mean
<bonniot>we must be safe in all cases, so for fail cases it does not matter if they are realistic or not, they must fail15:33
the question is to choose what we want to pass, in realistic cases15:34
<arjanb>i want 3 new things taking in assigment in account, merging branch at exit, delay capture of variable until closure declaration15:39
<bonniot>yes, that's reasonable15:40
<arjanb>and if the algorithm makes some unrealistic cases pass i don't mind15:41
<arjanb>safely ofcourse15:43
i will restrict myself to failures cases for the less realistic ones15:44
<bonniot>well, if more cases that are safe pass it's obviously a good thing15:45
i never said the contrary
it's just that it does not need to be a goal in itself
maybe i just look too much from the point of view of the algorithm i have in mind
i think implementing these 3 features with the current stack based implementing will be more complex15:51
if i had too much time i would implement both to compare15:52
<bonniot>more complex than implementing a full translation ast->ssi plus the algorithm itself? I would be surprised15:53
<arjanb>more complex as in harder to get correct and more difficult to reason about16:20
?String s = "abc";
s.substring(); //pass
try {
s = null;
s = "xyz";
} catch (Exception e) {
s.substring(); //fail
<bonniot>try/catch should be handled like an if I think16:23
enterIf, enterElse, exitIf
no, sorry16:24
at the entrance of catch, you must do a max between the current state and the before state16:25
<arjanb>wdym with before state?16:27
<bonniot>the state just before the try16:37
wait, that's not even correct
you need to compute a max during the try, and use that for the catch16:38
<arjanb>another issue is polymorphic local variables, i have no idea how that works and what the problems are16:49
<bonniot>it should be unrelated16:50
<arjanb>i find it behave a little strange with overloading16:53
<arjanb>let x = cast("abc");16:54
no error at compile time
Exception in thread "main" Argument #0 to 'java.io.File.length()' has wrong type
at gnu.mapping.WrongType.make(WrongType.java:56)
at testbug.fun.main(test.nice:9)
i didn't even import java.io16:55
<bonniot>let x = cast("abc"); is not a very good idea16:57
but yeah, this is strange
<arjanb>is the constraint of polymorpic variable shared between conditional branches?17:04
polymorpic variable don't influcence conditional types if the are of kind SomeClass<T>17:10
but if it is just T and i test that variable with instanceof, i not sure what effects that would have17:11
<bonniot>there is no interraction17:14
a type is associated with a variable, and will be used in all branches17:15
<arjanb>i'm missing something17:25
for a polymorpic variable you need to make sure that at every use the same instance of types is used right?17:26
<bonniot>yes, but this is done by instanciating with free type variables at the declaration, and these variables never change17:28
<arjanb>so every use of these variable add constraints to the free typevars?17:30
<arjanb>let x = cast("abc"); //cast just as example instead of reflection17:46
if (x instanceof String)
if (x instanceof Number)
what happens here with the free typevars?17:51
would it make sense to restrict polymorpic local variables to the ones having a concrete typeconstructor?18:01
<bonniot>your example depends on the type of instanceof18:03
with the current type, x is still unconstrained
<arjanb>doesn't the substring call constrain x?18:04
<bonniot>no, because x has the local type String in that branch18:05
<arjanb>hmm confusing18:13
<T> Collection<T> foo() = cast(new ArrayList());18:17
void main(String[] args) {
let x = foo();
if (x instanceof List)
if (x instanceof List)
in this case x seems to be constrained and gives an error on the second last line18:18
<bonniot>yes, there the list type parameter is constrained18:20
but you know, the implementation of local inference is not complete yet, as shown by the existing reports18:21
<arjanb>yes but it doesn't seem independent to rest of type inference to me18:25
i think polymorpic typed local variable without a typeconstructor doesn't add anything18:26
<bonniot>probably, but why make a special case?18:27
<arjanb>isn't it a special case already because of their conditional types are independent of the constraint?18:30
<bonniot>no, i don't see where is the special case18:32
<arjanb>ok i think i'm beginning to understand18:34
* CIA-2 leaves18:39
<arjanb>*away for meal
* CIA-2 joins18:44
* bonniot is away: ...18:48
* bonniot is back (gone 03:34:53)22:23
<arjanb>so how to proceed with the local type inference?23:02
btw have heard anything from adam?23:17
<bonniot>no, haven't heard since the last nice-devel message23:54
for lti, the first step should be to commit testcases to see we agree on those
then I think assignment could be implemented23:55
good night00:38
<arjanb>good night00:39
* bonniot leaves
* jys joins01:19
i got a question regarding nice sample using from java, is there anyone?01:20
that can help?
sorry i am so impolite
<arjanb>what's the problem?01:21
<jys>I tried to run the example from the manual : 01:22
Person p = new Person("John");
Worker w = new Worker("Julia", 1000);
with Person and Worker defined in a nice package
it's working well except that the dispatch generated class has no methods01:23
so the last line not compiling
Do u have any idea, i should have missed something obvious but i cannot see it.01:24
<arjanb>i most cases nicec compiles the methods inside the classes now
<arjanb>the manual is a little outdated, i think w.display() should work
<jys>ok so i have to call w.display()
<jys>as u just sayed
Thank u so much. I just discovered nice and i'am trying to use it01:26
it seem's really powerfull and well designed but it's true that the documentation is not giving it all credit it diserve01:27
<arjanb>if you find other outdated or unclear things in the documentation please let us know01:28
<jys>ok i'll let u know, i noticed some other thing weird to me in the manual, like beeing able to declare methods implementations in interfaces but maybe i just don't get it yet01:29
i'll try to understand and maybe i can help after that01:30
<arjanb>methods in interface is somewhat unusual at first but it's very usefull01:31
methods don't belong to classes in nice but are independent entities01:33
<jys>but why it is not an abstract class? I mean to my understanding an interface should not contain any implementation but i think i need to think more about al that
By the way just one last point, has method don't belong to classes how is it possible to protect things from beeing accesssed directly in classes (private has no sense?)01:35
<arjanb>visibiltiy modifiers aren't implemented yet but nice will get it01:37
Thanks for your help and congratulations for your work.01:38
<arjanb>'private' in nice will probably restrict access to a sourcefile instead of a class
you should thank daniel instead i just help a bit
<jys>yes, i already did it.01:39
Bye 01:41
* jys leaves
* arjanb leaves02:10

Generated by Sualtam