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

Using timezone: Central European Time
* arjanb leaves04:09
* bonniot joins08:38
* arjanb joins11:16
<bonniot>hi11:37
<arjanb>hi11:38
<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";
println(s.substring(1));
<bonniot>thx11:51
<arjanb>?String s = maybeString();
?String t = null;
if (s != null)
{
t = s;
println(t.substring(1));
}
<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)
println(s.substring(1));
void foo() { s = null; }
foo();
<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
ok?12:03
<arjanb>yes
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) {
println(s.substring(1));
s = maybeStringGenerator();
}
<bonniot>?String s ...12:08
<arjanb>indeed12:09
<bonniot>is this one not handled currently?12:10
<arjanb>this one should still work when the above testcase don't typecheck12:12
<bonniot>ok
for loops, doesn't it need a fixpoint computation?12:14
<arjanb>fixpoint?12:15
<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 {
typecheck(l.body)
} while(l.loopentryvariables.any(haschangedtype))
<bonniot>yes, that's it12:18
did you find an article about this problem?
<arjanb>no12:19
do you know any articles about that?12:20
<bonniot>no12:21
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);
println(s.substring(1));
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 {
x++;
s = "xyz";
if (x > 10)
break;
s = maybeStringGenerator();
} while (s == null);
println(s.substring(1));
<bonniot>and?12:39
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) {
x++;
s = maybeStringGenerator();
if (s != null)
break outer;
}
s = maybeStringGenerator();
} while (s == null);
println(s.substring(1));
<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(); }
foo();
c.contains(5);
<bonniot>ready to commit your testcases?14:21
<arjanb>i have to think about a few more testcase14:24
<bonniot>ok
<arjanb>why does assert only work for instanceof?14:25
<bonniot>what else?14:38
!= null ?
<arjanb>yes14:39
<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; }
foo();
foo();
println(t.substring()); //fail
multiple passes can be needed for closures14:47
?String s = "abc";14:50
void foo() { s = "xyz; }
foo();
println(t.substring());
<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(); }
foo();
s = null
foo();
<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
<bonniot>unrealistic?15:31
<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
<bonniot>unsafely?15:42
<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
<arjanb>agreed15:47
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;
maybeException();
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
<bonniot>how?
<arjanb>let x = cast("abc");16:54
println(x.length);
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
<bonniot>yes17:44
<arjanb>let x = cast("abc"); //cast just as example instead of reflection17:46
if (x instanceof String)
println(x.substring(1));
if (x instanceof Number)
println(x.intValue());
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)
x.add("abc");
if (x instanceof List)
x.add(5);
}
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
<arjanb>*back19:16
* 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?
<arjanb>hello
<jys>hello
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);
System.out.println(dispatch.display(w));
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
<jys>oh!01:25
<arjanb>the manual is a little outdated, i think w.display() should work
<jys>ok so i have to call w.display()
<arjanb>yes
<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
ok01:34
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
<jys>ok
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
<arjanb>bye
* jys leaves
* arjanb leaves02:10

Generated by Sualtam