forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Meeting weekly 2013 01 15
dherman edited this page Jan 15, 2013
·
2 revisions
dherman, azita, nmatsakis, jclements, pcwalton, brson, tjc
- FUEGO!
- topics on Patrick's whiteboard:
- move assert and log to macros
- conditions in
#[cfg()]
fn() unsafe { ... }
- where should we allow trait bounds?
- unsafe pointer indexing
[ u8 * CONST ]
- removal of "both type and trait" impls
-
Eq
andOrd
reform
- Graydon: tree's been on fire for over a week
- Patrick: none of us are hitting these LLVM issues and I don't understand them
- Patrick: still built-in; doesn't seem necessary
- Graydon: agreed
- Patrick: question with assert! makes it look like assert-not; had an idea whereby you could rename it failUnless but don't know whether people like that
- Patrick: bang doesn't look like not
- Graydon: wouldn't worry; think you have to understand id! means macro
- Dave: I agree with graydon
- Patrick: ok (consensus)
- Graydon: good luck figuring out how to do log
- Patrick: why hard?
- Graydon: flags
- Patrick: syntax extension, probably not macro
- Graydon: introducing syntactic elements that don't exist in language; we don't have mutable globals
- Patrick: interesting. we do have const in foreign mods; that lets you have unsafe reference to external; all we need is some way to define unsafe definition of an external
- Brian: const gives you mutable reference?!
- Patrick: immutable one
- John: what is the feature involved here?
- Graydon: global variables
- John: I'll just read up
- Graydon: logging is currently controlled by global variables injected by compiler
- Patrick: we can have the global variable in the runtime, write it in .c pending figuring out how to do it in Rust
- Graydon: but it's global per-module
- Graydon: this is why we've been blocked on this forever
- Patrick: I think we're gonna need to have unsafe globals for interacting with C code anyway
- Graydon: mostly agree
- Patrick: we'll figure it out
-
Patrick: only have
or
right now; would be nice to have conjunction and negation -
Patrick: I propose: if you specify multiple conditions they're anded, and you can say
not(--)
- Patrick: that's minimal. we could have and and or operators
- Graydon: comma-separated seems fine
- Patrick: basically gives you disjunctive normal form
- Brian: agree
-
Patrick: diff between
fn unsafe
andunsafe fn
-- originally we were like what? - Patrick: general chatter was this wasn't great
- Brian: I tried to remove it once, didn't like it
- Brian: wouldn't mind removing it though
-
Patrick: I never write
fn unsafe
- Graydon: I'd be in favor of removing
- Patrick: just a form that only exists in statement or expression position
- Brian: not gonna lose any sleep if you remove it
- Patrick: sympathize with brevity, but I worry this is the one form that needs to be unambiguous (consensus)
- Patrick: currently allow in weird places like structs
- Patrick: don't enforce them there
- Niko: we do, probably not correctly, but we try to
- Patrick: feel like having a trait bound in data (structs, enums, etc) is kind of weird overlap of functionality of trait bounds in code (fn, impl)
- Brian: can't use them till you call a function
- Patrick: don't really serve any purpose
- Niko: can't ever construct an instance that's not e.g. Eq-able
- Niko: when we had class syntax they made more sense
- Brian: user could create your data type, violating some of your intended invariants
- Patrick: if you export the constructor
- Patrick: if not, you control it
- Niko: if you export the type it has a literal form
- Niko: we had this discussion once before I thought
- Graydon: feel like we've discussed this
- Niko: if we ever want them we can put them back
- Graydon: no one's gonna put anything there in the syntax anyway, totally future-proof
- Patrick: ability to index into unsafe pointers -- people want this
-
Brian: never felt need for it;
offset
method gives you offset - Niko: no strong opinion
- Patrick: maybe let's not worry about it
- Graydon: why can't use index method?
-
Patrick: unsafe;
index
method doesn't have unsafe bound on it - Niko: you have to build it in if you want it
-
Niko: can certainly support
+
and arithmetic - Niko: I don't really care
- Graydon: discourages people from doing it, which is good
- Patrick: okay, let's not do it
- Patrick: every other day someone comes in and asks how to create a fixed-length vector with a const
- Patrick: concerned about cycles: consts are type-annotated, so creates weird cycle between type resolution and const evaluation
- Patrick: given thought in different ways. way I like best: remove field projection from const evaluation language, then nice bottom-up phenomenon: means you can evaluate all the numeric constants without evaluating any other constants
- Niko: do we have array-indexing?
- Patrick: have to remove that too if so
- Dave: still have to do cycle detection between const variable declarations, right?
- Patrick: yes, already do. const-and-type cycles is the hard one
- Niko: I'm in favor of this
- Graydon: I'm in favor of this, if you talk about removing those two operators from the integer constants
- Graydon: if you look at work in constants, there's three expression grammars: full, const, and int const expressions -- latter are ones that can serve as enumerator values; they're the ones that should be here as well; array sizes should only be int const expressions
- Niko: not just property of expression that appears in that position, but any variables referenced by that expression, right?
- Graydon: yes, it's a deep property
- Patrick: this exists today?
- Graydon: believe if you look at constant classification code
- Niko: guess that's a compromise: evaluate those constants that appear in those positions early... (cut off)
- Patrick: all consts that have scalar values, just make them always integer?
- Niko: didn't think that's what he's saying. think he's saying const of some types can use field projection, other types not
- Niko: seems weird
- Dave: not clear what Graydon means, let's let him explain G:
- Niko: Four examples:
// Example 1:
const foo: uint = ...;
let x: [int * foo] = ...;'
// Example 2:
struct S { f: uint }
const foo: S = ...;
let x: [int * foo.f] = ...;'
// Example 3:
struct S { f: uint }
const foo: S = ...;
const bar: uint = foo.f;
let x: [int * bar] = ...;'
// Example 4:
struct S { f: uint }
const foo: S = ...;
const bar: uint = foo.f;
/* bar is never used in a type context */
// Example 5:
struct S { f: uint }
const foo: S = ...;
const bar: S = S { f: foo.f };
// Example 6:
struct S { f: uint, g: [u8 * bar] }
const foo: S = S { f: bar, g: [ 1, 2, 3, 4, 5 ] };
const bar: uint = foo.g[0];
- Graydon: all I'm saying is int constant category is what we should use in array bounds
-
Niko: seems to me that's insufficient. have these 4 examples; what I'm concerned about is... sounds like bad case is ex 3: expression is simple, but definition of
bar
requires a field projection - Niko: difference between that and ex 4 is constant is never used in a type context; patrick said maybe all uints should be simple, but that's pretty restrictive
- Dave: concerned the distinction between simple/non-simple expressions will be hard to understand, and the errors will be hard to diagnose
- Graydon: why does turning off subsections of grammar make the problem any easier? you still have to check for cycles, right?
- Patrick: but then you have to check for cycles between constants and types
- Graydon: but there's no way for a constant to be defined in terms of a type
- Patrick: but constants have to be type-annotated; type checker currently works by doing type collection first -- that now has to be intertwined with constant-evaluation
-
Dave: oh, cycle example:
const i: [ u8 * i ] = ...;
- Niko: we can detect these cyclic conditions, but I think what patrick's objecting to is big phase that does types and constants altogether
- Niko: in patrick's scheme they wouldn't be intertwined
- Graydon: well, int constants
- Niko: but int constants can refer to arbitrary types
- Niko: if you remove field projection, int constants only ever refer to int constants
- Graydon: I'm fine with that restriction in int constants, which are the only thing involved in this early pass
- Niko: seems weird to me to have different legal expressions based on type of constant
-
Graydon: no, it's already true. because
&
is legal here. int constants get put in memory in a place - Niko: don't understand
- Graydon: every constant that is not an integer constant is semantically and importantly semantically different. not just a value, but a place in memory. has an address that can be taken
- Niko: that's not necessary
- Graydon: it is necessary
- Niko: why? could take address of any constant
- Graydon: couldn't use in an integer constant in a type
- Graydon: can cast pointers to integers
- Niko: don't think we allow that in safe code, do we? we shouldn't
-
Niko: don't think you can cast
&T
- Graydon: uncomfortable pretending addresses don't exist
- Niko: can find out what they are through unsafe code. it's unsafe if we go to moving GC, for example
- Niko: so you'd be happier if constants with integral type are special category
- Dave: if there are important semantic distinctions, there should be important syntactic distinctions to make that clearer
- Patrick: not totally convinced of utility of field projection in constants anyway
- Niko: not convinced about field projections. seems like you could pull out that value...
- John: error message is gonna be unfriendly: b/c this thing turned out to be int, not allowed to do field projections
- Graydon: this is completely normal in C-family languages
-
Graydon: they have
sizeof
- Patrick: that's not a field projection
- Graydon: same effect, creates backwards projection with cycles
- John: doesn't that argue for Dave's scheme?
- Niko: argument we should just do the combined phase.
- Dave: if we do that, don't need the syntactic distinction as much
- Patrick: maybe we should just combine
- Niko: not so sure. would also require that we type check constant expressions, b/c we have to be able to evaluate them.
- Niko: right now: first we create the types, then can type check
- Dave: could sort of do "dynamic typing" -- check as you const-evaluate
- Niko: seems painful, anyway
- Patrick: could create graph of types and topologically sort, that gives you an evaluation order
- Dave: this is likely to get over-complicated
-
Graydon: lemme play devil's advocate against my own position. we've been conservative b/c it's hard to decide. one reason we've resisted
sizeof
so long -- it's junky. target-dependent. and it's not even enough; you end up withalignof
... we have difficulty with native C libraries that present partial types or whose size depends on size of other types; don't think those patterns are gonna go away. - Graydon: anyway I agree this complicates the type checker
- Patrick: C doesn't have cyclic dependencies so it's easier for them
- Niko: do we use field projection in const-expressions?
-
Patrick: problem is
sizeof
really - Niko: not so bad b/c you know what its type is
- Patrick: no you don't
-
Niko: you can scan for
sizeof
in AST and find it; induces a dependency, yes, but I don't think it's... not same thing. doesn't require you have full... - Graydon: seems like a chat with community might help, background research on other languages
- Graydon: don't have quite enough to decide right now
- Patrick: ok, that's fine
- Graydon: I'm not wedded to field projection, but it's a bigger problem
-
Patrick: that's completely right,
sizeof
is also important to consider
-
Patrick: if you're in same module as
T
and you writeimpl T : tra
then methods in that impl are available in both the type and the trait, but not if you're in a different module - Patrick: this behavior is surprising, will probably lead to name conflicts
- Patrick: would like to remove it
- Brian: agree
- Graydon: agree
- Niko: agree
- Patrick: don't quite know what to do
- Patrick: design space
-
Patrick: currently
Eq
andOrd
are good for partial but not so good for total. derivingOrd
is not particularly efficient sincelessThan
andeq
are different methods. - Niko: I think the efficiency question is not even necessary. correctness of hashtables is based on...
- Patrick: compare the efficiency of these two approaches:
// C++-like Ord
impl<T:Ord,U:Ord> (T,U) : Ord {
fn lt(&self, other: &(T,U)) -> bool {
if fst(self) < fst(other) {
true
} else if fst(self) > fst(other) {
// two comparisons between fst(self) and fst(other) :(
false
} else {
snd(self) < snd(other)
}
}
}
// Haskell-like Ord (also Java)
impl<T:Ord,U:Ord> (T,U) : Ord {
fn ord(&self, other: &(T,U)) -> Ordering {
match fst(self).ord(fst(other)) { // one comparison
Less => Less,
Greater => Greater,
Equal => snd(self).ord(snd(other))
}
}
}
- Patrick: correctness of hashtables: if you put NaNs as key in hashtable, you're going to have pain
- Dave: haha, dealing with this in JS too
- Patrick: because NaN != NaN
- Patrick: fundamental issue is that there's partial vs total, two different interfaces
- Patrick: hash tables and binary search trees want total equality and total ordering, respectively
- Patrick: for ordinary arithmetic operators, you typically want the partial equality and partial ordering
- Brian: why do you want that?
- Patrick: 1) expectation based on IEEE, 2) efficiency in hardware
- Dave: the hardware point is the compelling one, trumps everything
- Patrick: C++ says putting NaN in hashtable is undefined behavior; always use partial equality
- Patrick: Haskell says: we are not IEEE 754, everything is total
- Patrick: as a result, not sure they can use most efficient fp hardware
- Patrick: neither seems particularly ideal. feel that both are suboptimal
- Dave: sounds like you want 4 interfaces; worry about complexity
- Patrick: other problem: what do the operators mean
- Patrick: derive PartialEq and TotalEq, one for operator, one for hashtable; not great
- Patrick: also can't use operator for the impl of hashtable, could be slow
- Graydon: I'm not following. why does hashtable want total equality? why is it undefined in C++?
- Patrick: if you put NaN in, can't get it out again
- Graydon: what does a normal C++ library actually do?
- Patrick: don't know
- Niko: depends very much on precise way they wrote that loop (e.g., whether they use == or !=)
- Graydon: when you say partial equality, you mean one where they can both be false?
- Niko: yeah
-
John: wait, does
NaN != NaN
return true or false? - Dave: true
- Dave: I tend to think that the nature of floating point is that it's hazardous
- Patrick: not so simple because of example code above
-
Patrick: wait, for binary search trees, you really want the
ord
method, not less-than -
Patrick: proposal: Three traits:
- Eq is a partial ordering.
- Cmp gives you the operators <, <=, >=, and >, and is partial.
- Ord is the "ord" function and is a total ordering.
- Brian: I don't understand why this is better if hashtables are still broken for floats
-
Patrick: here's why I like this: < is not what you want for binary search trees; they want
ord
. andord
can be efficiently implemented for substructures -
Brian: so regardless of float problem want
ord
-
Niko: arguably could use
ord
for hashtables -
Niko: float would be instance of
Ord
using Java ordering -
Brian: because
Ord
providesEq
, doesn't matter ifEq
is total - Patrick: I'm not sure about solving for hashtables
- Brian: thought that was whole motivation
-
Patrick: there are many. biggest is that I can't implement
deriving Ord
efficiently -
Brian: okay. only matters for hashtables. everyone else uses
Cmp
. those are still gonna be same thing as always. where does this matter? who will useOrd
? - Patrick: binary search trees
-
John: current proposal is hash requires
Eq
orOrd
? -
Patrick: prefer
Eq
and don't care about NaNs - Niko: me too
- John: could be security issue. could get back somebody else's value if you ask for NaN
- Niko: how?
- John: no, I take it back
-
Dave: would urge us to have very clear, carefully written documentation clearly explaining when to use
Cmp
vs when to useOrd
-- otherwise people will find it confusing -
Dave: should
Ord
<:Cmp
? since they're related -
Patrick: no because
ord
doesn't use less-than - Niko: hm, unclear... they could
- Patrick: this solution doesn't solve float at all
-
Patrick: sort of hackishly solves floats with
Ord
-
Patrick: if we really wanted to solve it, we'd have
TotalEq
andPartialEq
- Dave: haven't understood the deriving part of this issue
-
Patrick: want deriving to generate optimal code, but I can't without
Ord
- Dave: sounds like you should give this some more thought and present it next week
- Niko: or write it up. I think this is the most plausible solution
-
Dave: no relationship between
Cmp
andOrd
? - Niko: yes. reason is float -- have both a partial and total ordering, so can't just have one trait hierarchy
- Dave: really think we should have a well-written rationale as well as clear guidelines for use
- Niko: yeah