Re: [rust-dev] Higher-Kinded Types vs C++ Combos

2013-12-07 Thread David Piepgrass
(Another big reason I like forums over mailing lists, which I forgot to
mention in that other thread, is that I can fix my mistakes!) Typo
correction:

struct ListTrait
{
templatetypename T typedef listT collection;
};

And I'd rephrase my third question:
3. If Rust had C++-style typedefs, would it make sense to argue that we
don't need Higher-Kinded Types, we can just use typedefs for everything?

In case people are finding the Combo concept hard to follow, I will offer
GiST (http://en.wikipedia.org/wiki/GiST) as a concrete example. A GiST has
a few different parts, each of which can be swapped out to produce
different kinds of trees. When I tried to implement the GiST in C#, I found
that I wanted 8 type parameters on the GiST base class:

- The derived tree type
- The internal node type
- The leaf node type
- The compressed left entry type
- The uncompressed leaf entry type
- The compressed internal entry type
- The uncompressed internal entry type
- The key type (type of data stored in an entry)

This, of course, is utterly impractical when they have to be listed
repeatedly, every time the base class is mentioned. I figured out how to
whittle it down to one parameter on the base class and two elsewhere, but I
had to restructure the code in some unnatural ways, so the readability of
the code was substantially harmed, and there was some performance cost as
well (some interfaces, some virtual methods, more casts.)

Even with one or two type parameters, the names of things were still
unweildy because often the concrete type parameters were themselves
parameterized.

Of course, type parameters are not the only way to do a GiST. It can also
be done by defining everything in terms of interfaces (or in Rust, trait
objects). But this implies that when the different parts of the code
interact, they must use dynamic dispatch. Even worse, although the entries
(leaf/internal, compressed/uncompressed) are small implicitly-copyable data
types (let's say 8 - 32 bytes typically, though I don't have the code
handy), most of the code will be unaware how large or small each entry is,
so the entries would (in C# at least) have to be stored on the heap, rather
than passed around directly as structs (I'm not sure what you'd do in Rust).

Thus, if you want to implement a GiST in C# you get either hard-to-follow
code with sub-optimal performance, or straightforward code with terrible
performance. The third alternative, of course, is to not implement a GiST,
but implement each kind of tree (B+ tree, R-tree, ...) separately. This
requires code duplication and repeated design work, the elimination of
which was the reason GiSTs were invented in the first place.

In Rust, I assume you could use macros to overcome some of the problems
that make a GiST difficult to do in C#. However, I am thinking that if
typedef is in some ways a more powerful concept than HKT, arguably Rust
should support them first or investigate whether they can be generalized to
do what HKTs were meant to do.


On Sat, Dec 7, 2013 at 12:10 AM, David Piepgrass qwertie...@gmail.comwrote:

 Rust newb here. I have theoretical questions.

 Recently I noticed that Higher-Kinded Types (HKTs) have been mentioned on
 the mailing list a lot, but I had no idea what a HKT was, or what it might
 be good for. After reading about them a little, they reminded me of C++'s
 template template parameters. In C++ you can almost write something like
 this:

 template template typename class collection
 struct Numbers {
collectionint integers;
collectionfloat floats;
 };

 So then you can write Numbersvector for a structure that contains
 vectorT collections, and Numberslist for a structure that contains
 listT collections. EXCEPT that it doesn't actually work, because
 vectorT has two template parameters (the second one, the allocator, is
 normally left at its default). Let's ignore that, though.

 So that brings me to my first question: is this what higher-kinded types
 means? What is the difference, if any, between HKT and C++ template
 templates?

 However, as a C++ developer I never actually used a template template
 parameter because I didn't know they existed for a long time. So instead I
 would have written this, which has the same end-result:

 struct VectorTrait
 {
 templatetypename T
 struct collection { typedef vectorT type; };
 };
 struct ListTrait
 {
 templatetypename T
 struct collection { typedef listT type; };
 };

 templatetypename Traits
 struct Numbers
 {
 Traits::collectionint::type integers;
 Traits::collectionfloat::type floats;
 };
 // Use NumbersVectorTrait for vectorT, NumbersListTrait for listT.

 This is clunkier, but it would have been a bit simpler if C++ supported
 templatized typedefs:

 struct VectorTrait
 {
 templatetypename T typedef vectorT collection;
 };
 struct ListTrait
 {
 templatetypename T typedef vectorT collection;
 };

 templatetypename Traits
 struct Numbers
 {
 Traits::collectionint

[rust-dev] Higher-Kinded Types vs C++ Combos

2013-12-06 Thread David Piepgrass
Rust newb here. I have theoretical questions.

Recently I noticed that Higher-Kinded Types (HKTs) have been mentioned on
the mailing list a lot, but I had no idea what a HKT was, or what it might
be good for. After reading about them a little, they reminded me of C++'s
template template parameters. In C++ you can almost write something like
this:

template template typename class collection
struct Numbers {
   collectionint integers;
   collectionfloat floats;
};

So then you can write Numbersvector for a structure that contains
vectorT collections, and Numberslist for a structure that contains
listT collections. EXCEPT that it doesn't actually work, because
vectorT has two template parameters (the second one, the allocator, is
normally left at its default). Let's ignore that, though.

So that brings me to my first question: is this what higher-kinded types
means? What is the difference, if any, between HKT and C++ template
templates?

However, as a C++ developer I never actually used a template template
parameter because I didn't know they existed for a long time. So instead I
would have written this, which has the same end-result:

struct VectorTrait
{
templatetypename T
struct collection { typedef vectorT type; };
};
struct ListTrait
{
templatetypename T
struct collection { typedef listT type; };
};

templatetypename Traits
struct Numbers
{
Traits::collectionint::type integers;
Traits::collectionfloat::type floats;
};
// Use NumbersVectorTrait for vectorT, NumbersListTrait for listT.

This is clunkier, but it would have been a bit simpler if C++ supported
templatized typedefs:

struct VectorTrait
{
templatetypename T typedef vectorT collection;
};
struct ListTrait
{
templatetypename T typedef vectorT collection;
};

templatetypename Traits
struct Numbers
{
Traits::collectionint integers;
Traits::collectionfloat floats;
};
// Now write NumbersVectorTrait instead of Numbersvector,
//   NumbersListTrait instead of Numberslist.

I have found that because of the existence of typedef, template template
parameters are never actually necessary; so far, I've never seen a
situation where the typedef-based solution wasn't almost as good. Also, I
have found that trait types filled with typedefs seem to be a more
general thing than template template; they allow you to do things that
would be very difficult or impossible without them. For example you can use
typedefs-in-a-struct to create circular references among types that don't
know about each other:

// I call this a Combo; I don't know if the technique has a standard name
struct MyCombo {
typedef ConcreteATraits A;
typedef ConcreteBTraits B;
typedef ConcreteCTraits C;
};
templatetypename Combo
class ConcreteA { Combo::B* b; ... };
templatetypename Combo
class ConcreteB { Combo::C* c; ... };
templatetypename Combo
class ConcreteC { Combo::A* b; ... };

Here I've created a network of types (ConcreteAMyCombo,
ConcreteBMyCombo, and ConcreteCMyCombo) that are linked together
through the Combo type MyCombo, so the types can all use each other, but
none of the types refer to each other directly. This design allows you to
freely swap in different implementations of A, B, and C; it has similar
advantages to dependency injection or inversion of control in languages
like Java and C#, except that the linkages are all defined statically at
compile-time, so no dynamic dispatch is required.

Without the ability to define typedefs, this approach is not possible at
all if there is a cyclic relationship. Also, if the combo declares more
than three types, it becomes impractical to specify all those types on the
classes directly as type parameters.

In C# I learned that this quickly becomes a major problem if you need to
parameterize on more than one or two types. I tried to do generic math
(which requires at least two type parameters due to the under-designed
standard libraries) and I also implemented a GiST data structure (see
http://en.wikipedia.org/wiki/GiST), and found out that the lack of any
analog to C++ typedef makes both of those tasks very clumsy, while also
making the code hard to read, because you end up with a rats' nest of type
parameters (or if you omit (otherwise necessary) type parameters, you might
use lots of casts instead.)

So I guess that leads me to two more questions.

2. Does Rust have a typedef equivalent that can be used in this way?
3. Does it make sense to just suggest just use typedefs instead of
Higher-Kinded Types?
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Persistent data structures

2013-12-04 Thread David Piepgrass
My next goal is a persistent tree-map, probably cribbing from Haskell's
Data.Map.

I look forward to hearing how that goes!

I've been meaning to make a data structure in Rust too, but it's hard to
find the time, so how's about I tell you guys about it instead.

I call my data structure an optionally-persistent hashtable or hashset.
In C# I implemented this optionally-persistent hashtable and hashset with
mutable and immutable variants of each (the term semi-persistent was
already taken and means something else). I've been meaning to write an
article about this, but didn't get around to it yet.

Optionally-persistent means that it's structured as if it were persistent,
but each node can be either mutable (locally) or immutable (recursively).
Each node has a frozen flag which implicitly applies recursively to all
children. Converting the tree from immutable to mutable, or mutable to
immutable takes O(1) time. Immutable to mutable is essentially a no-op (the
mutable copy has copy-on-write behavior), while mutable-to-immutable simply
requires marking the root node as frozen.

The hashtable is really a tree that is up to 8 levels deep, with each
level representing 4 bits of the hashcode (not sure if this is the best
approach). Lots more details in the doc comment:

https://sourceforge.net/p/loyc/code/HEAD/tree/Src/Loyc.Collections/Sets/InternalSet.cs

My benchmarks show that mutating such a set/map is dramatically faster than
immutable editing (which requires copying multiple nodes for each change),
and not that much slower than a traditional hashtable, so I think it's
hands down superior to a traditional persistent hash tree.

In my version, from the end-user's perspective, there's a separate data
type for immutable and mutable versions of the data structure (MMapT and
MSetT are mutable, MapT and SetT are immutable). Both data types
encapsulate an instance of InternalSetT which is the real data
structure. InternalSetT manages a tree of nodes, where each node has 16
entries and represents 4 bits of the hashcode. There's also an interesting
variation called InvertibleSetT; an invertible set can represent a
negative set such as all integers except 0 and 1.

-- 
- David
http://loyc-etc.blogspot.com
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Persistent data structures

2013-12-04 Thread David Piepgrass
Please disregard this message; I hadn't seen Bill Myers' solution
(copy-on-write
by cloning only when reference count  1), which sounds like it's probably
perfect for Rust.


On Wed, Dec 4, 2013 at 9:03 PM, David Piepgrass qwertie...@gmail.comwrote:

 My next goal is a persistent tree-map, probably cribbing from Haskell's
 Data.Map.

 I look forward to hearing how that goes!

 I've been meaning to make a data structure in Rust too, but it's hard to
 find the time, so how's about I tell you guys about it instead.

 I call my data structure an optionally-persistent hashtable or hashset.
 In C# I implemented this optionally-persistent hashtable and hashset with
 mutable and immutable variants of each (the term semi-persistent was
 already taken and means something else). I've been meaning to write an
 article about this, but didn't get around to it yet.

 Optionally-persistent means that it's structured as if it were persistent,
 but each node can be either mutable (locally) or immutable (recursively).
 Each node has a frozen flag which implicitly applies recursively to all
 children. Converting the tree from immutable to mutable, or mutable to
 immutable takes O(1) time. Immutable to mutable is essentially a no-op (the
 mutable copy has copy-on-write behavior), while mutable-to-immutable simply
 requires marking the root node as frozen.

 The hashtable is really a tree that is up to 8 levels deep, with each
 level representing 4 bits of the hashcode (not sure if this is the best
 approach). Lots more details in the doc comment:


 https://sourceforge.net/p/loyc/code/HEAD/tree/Src/Loyc.Collections/Sets/InternalSet.cs

 My benchmarks show that mutating such a set/map is dramatically faster
 than immutable editing (which requires copying multiple nodes for each
 change), and not that much slower than a traditional hashtable, so I think
 it's hands down superior to a traditional persistent hash tree.

 In my version, from the end-user's perspective, there's a separate data
 type for immutable and mutable versions of the data structure (MMapT and
 MSetT are mutable, MapT and SetT are immutable). Both data types
 encapsulate an instance of InternalSetT which is the real data
 structure. InternalSetT manages a tree of nodes, where each node has 16
 entries and represents 4 bits of the hashcode. There's also an interesting
 variation called InvertibleSetT; an invertible set can represent a
 negative set such as all integers except 0 and 1.

 --
 - David
 http://loyc-etc.blogspot.com




-- 
- David
http://qism.blogspot.com
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Rust forum

2013-12-03 Thread David Piepgrass
  David Piepgrass qwertie...@gmail.com wrote:
   Okay, well, I've never liked mailing lists at all, because:
  
   1. In non-digest mode, My inbox gets flooded.
   2. In digest mode, it's quite inconvenient to write a reply, having to
   cut out all the messages that I don't want to reply to and manually
 edit
   the subject line. Also, unrelated messages are grouped together while
   threads are broken apart, making discussions harder to follow.
   3. In email I don't get a threaded view. If I go to mailing list
 archives
   to see a threaded view, I can't reply.
 
  Just use NNTP (gmane.comp.lang.rust.devel on news.gmane.org). Most
  newsreader support threaded view (Thunderbird does). You can configure
 the
  mailing list s.t. mails are not actually delivered to your email address
  even if you are registered.
 
  But looking at your email address you are already using gmane.

 I'm using gmail; I have never used gmane and know nothing about it. I also
don't have or use an email client or a newsreader. And there are lots of
people like me.

If gmane is the preferred way to interact with this mailing list, users
clicking on the mailing list link:

https://mail.mozilla.org/listinfo/rust-dev

should be pointed at gmane specifically.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Rust forum

2013-12-02 Thread David Piepgrass
Hey, why not set up a Discourse forum? That would be so. much. better. than
a mailing list. As an OSS dev I've been itching to get one myself, but
don't have time or much money to set it up. For Mozilla, though? No problem
I'm sure.

http://www.discourse.org/
Google: discourse hosting.
http://www.google.com/search?q=discourse+hosting


From: Eric Reed ecr...@cs.washington.edu
 ...
 I'm not aware of any plans for a rust-users forum. Maybe spinning a
 rust-users mailing list off from rust-dev would make sense? We already did
 a similar thing with our IRC channels.


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Rust forum

2013-12-02 Thread David Piepgrass
On 02/12/2013 16:21, David Piepgrass wrote:

  That would be so. much. better. than a mailing list.

 Hi. Could you expand on this? I don?t necessarily disagree, but as the
 one proposing change it?s up to you to convince everyone else :)

 --
 Simon Sapin


Okay, well, I've never liked mailing lists at all, because:

1. In non-digest mode, My inbox gets flooded.
2. In digest mode, it's quite inconvenient to write a reply, having to cut
out all the messages that I don't want to reply to and manually edit the
subject line. Also, unrelated messages are grouped together while threads
are broken apart, making discussions harder to follow.
3. In email I don't get a threaded view. If I go to mailing list archives
to see a threaded view, I can't reply.
4. I have to manually watch for replies to my messages or to threads I'm
following. If someone mentions my name (not that they would), I won't be
notified.

In contrast, Discourse has a variety of email notification options. I don't
know if those options are enough to please everybody, but you can probably
configure it to notify you about all posts, which makes it essentially
equivalent to a mailing list. It supports reply by email, so those that
prefer a mailing list can still pretend it's a mailing list. Currently I'm
getting an shrunk digest of Discourse Meta--by email I only get a subset of
all messages, auto-selected by Discourse, whatever it thinks is
interesting. That's good for me: I really don't want to see every message.

Plus, a mailing list offers less privacy as it mandates publishing your
email address. That's not a big deal for me personally, but do you really
want to require that from every Rust user?

(btw, if I'm wrong about any of the above points, I promise there are lots
of other netizens out there who have the same misconception(s), so many of
them will avoid mailing lists. The fact that y'all are talking to me on a
mailing list suggests that the disadvantages of a mailing list are not a
big deal *to you*, but as for those who aren't participating, you can't
conclude *they* prefer mailing lists.)

And like mailing lists, Discourse also supports private messages.

I don't understand why Paul mentioned GPG. You want to encrypt messages to
a public mailing list? You can sign messages, but surely almost no one
actually checks the signature, and I'd be surprised if Discourse didn't
offer some built-in evidence of identity (surely it's not like email in
letting you spoof the sender name easily?).

I heard discourse supports attachments, just that you may have to go to the
forum to attach or download them (rather than by email).
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Removing some autoref magic

2013-11-20 Thread David Piepgrass
I'm wondering something. Have the Rust developers considered the
possibility of using references instead of pointers? It seems to me
that this would eliminate a lot of the need for autoderef. Now I'm
not well-equipped to talk about Rust (some of the rules I am totally
ignorant about, e.g. I know rust has a ref keyword but the tutorial
does not mention it) so let me talk about C++ instead.

C++, of course, has references, which are exactly like pointers except
they are always implicitly dereferenced:

int y = 123;
int* x1 = y; // *x1 == y   x1 == y
int x2 = y;  //  x2 == y  x2 == y

In fact, with one small tweak, C++ could have entirely eliminated the
need for pointers (except array pointers), and references could have
been used for everything except arrays. The reason references cannot
replace pointers is that the pointer--the true identity of a
reference--is immutable. But that's easily fixable though, by defining
x2 as an lvalue:

x1 = z;
x2 = z; // Aha! We've changed the pointer inside the reference

If the second line were legal, then references could do everything
that pointers could do; in that case I think that, for consistency,
people would have eventually standardized on using references for
everything that doesn't require pointer arithmetic (i.e. arrays).
Instead we have this situation where some functions take (non-const)
T and others take T*, so sometimes you have to call functions with
foo and other times it's just foo, and the presence or absence of
 doesn't signify anything important (for example, it doesn't tell
you whether the callee mutates foo or not)

It seems to me that the majority of languages have recognized that
references are easier to work with than pointers, and not just because
you can write foo.f() instead of foo-f(). That is, I don't think
auto-deref (where foo.f() means (*foo).f()) is enough to eliminate the
pain of working with pointers instead of references.
Would it help to define ~T, T and @T as reference types rather than
pointer types? I'm sure there are some obvious objections, but perhaps
the problems could be ironed out by someone with a better grasp of
Rust.
I'd also like to comment on the removal of move. While I recognize
explicit moves everywhere might be inconvenient, I have noticed that
newbies on the list (including myself) are often confused by them.
Would a compromise be in order, in which moves are implicit except
when passing parameters to methods? I like Bill Byers' suggestion for
call-site parameters of the form move x, mut x and just x for
implicit copy / borrow. Patrick mentioned the annoyance of writing

 let move x = move foo(move y);

but


 let x = foo(move y);

doesn't sound so onerous, and it says something important about foo()
that someone reading the code might not realize.

Everyone's had their fair share of issues with autoref and autoderef,

and it's worth considering removing certain portions of it from the

compiler. The discussion around this has been rooted in the past, but

has recently been brought up as part of

https://github.com/mozilla/rust/issues/10504.


 The current proposal is to remove all autoref except for function

invocations and indexing operations. The method of creating T from ~T

would be `let foo: T = foo` or `*foo`. Vectors and strings can't

currently benefit from the `*foo` syntax, but they will hopefully be

able to do such once DST lands. In the meantime coercion via type

ascription will work and they also have `as_slice` methods.


 There are a few reasons backing this proposal:


 1. It's inconsistent to have magical autoref in some places, but not

in other places.

2. The camp of less compiler magic is better can fly their flag over

this change.

3. Code readability does not necessarily benefit from autoref on arguments:


   let a = ~Foo;

  foo(a); // reading this code looks like it moves `a`

  fn foo(_: Foo) {} // ah, nevermind, it doesn't move `a`!


   let mut a = ~[ ... ];

  sort(a); // not only does this not move `a`, but it mutates it!



___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Type system thoughts

2013-11-16 Thread David Piepgrass
 Personally I'd appreciate a type system that's able to express SI units,
which C++ and Haskell are powerful enough to do[1].

I agree. This is of huge importance when it comes to providing compile
time safety guarantees. And if the language is powerful enough to express
SI units, then it also demonstrates that it might be powerful enough to
allow users to grow the language in other directions not anticipated by the
language designers.

While I'm no type system expert, I implemented a unit inference system for
boo (though boo's developers weren't interested and did not use it). So I
thought I'd just share some thoughts about how I view types and unit
checking (as someone whose university education included absolutely no type
theory).

I've started to view types as three partly or wholly independent elements:

1. Physical structure. Under this view, two structs with members x: int,
y: int can be considered the same structure, and while direct assignment
between them may not be allowed, the compiler can safely treat them as the
same type IF the language allows it to.
2. Name and attributes. This encompasses things like names and modules
where structures live (e.g. a Point structure defined in two different
namespaces), const/non-const in C++, mutable-immutable in D, and units
(km/L, bytes/sec). Unlike a typing error in (1), a typing error or cast
that changes these attributes does not compromise the memory safety of the
language.
3. Operations. Often a type has multiple interfaces, e.g. in Java, an
object can be accessed through several different interfaces without
changing its type. I've been designing a language where this is extended to
allow arbitrary user-defined views on a type (a concept which might be
very useful in my Loyc project, whose goal is to allow cross-language
programming; often there are some types in two different languages that are
very similar and just need someone to define a mapping between them.)

I wonder if anyone has formalized a view like this before.

Anyway, viewing (2) as a plurality of attributes, independent from (1),
might allow one to develop a type system where user-defined attribute
typing is straightforwardly possible. A simple version of this would be to
allow users to install a plug-in shared library that the compiler uses for
additional analysis following standard typing. Then unit inference could be
installed as one such library. These libraries would not necessarily be
allowed to change the behavior of the program; it would be useful enough
just to allow them to perform analysis, but it would be more useful if they
could alter behavior too (e.g. the unit-checking module could automatically
coerce km to mi or m or yd, adding a scaling factor; or in a
language with overloading, functions could be overloaded based on unit
types.)

Note that typing failure in (2) need not prevent the code from being
compiled (in general I like a language that doesn't force me to fix every
little problem before running the code.)

A general facility for annotating code is necessary to allow extra typing
without changing the language grammar (e.g. in my languages LES and EC# my
expression grammar allows attributes in [SquareBracks] at the beginning of
any expression or subexpression in parentheses, plus I support some
user-defined operators.)

One thing I want to say about unit checking, it's much more useful to
provide unit inference rather than unit checking, because users don't want
to write annotations all over the place. A function like

fn abs(x: int) - int { if x  0 { -x } else { x } }

should need no annotation for the unit inferer to understand that 'x' has
polymorphic units, and in

fn length(self) { sqrt(self.x * self.x, self.y * self.y) }

'x' and 'y' can be constrained automatically to have the same units. (there
are a bunch of subtle details of course, but since I wrote the inference
engine about 7 years ago, I forgot many of them...)

-- 
- David
http://loyc-etc.blogspot.com
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Abandoning segmented stacks in Rust

2013-11-05 Thread David Piepgrass
Segmented stacks aren't the only solution though.

If the concern is many tasks that block for a long time, I imagine a
mechanism to bundle a bunch of small, dormant stacks into a single page so
that the original pages could be released to the OS.

If stacks were additionally relocatable (which requires similar machinery
as precise moving GC, if I'm not mistaken) then the released pages could be
re-used for other tasks or heaps, which would be especially helpful on
32-bit. To address the problem of running out of address space on 32-bit,
small-stack tasks could request a single-page stack (plus a guard page),
which is enlarged by relocation as needed.

Combining these techniques, you might be able to have up to a million small
tasks in a 32-bit process.

From: Bill Myers bill_my...@outlook.com

 The advantage of segmented stacks is that blocked tasks only take up as
 much memory as they actually need to store state, so that for instance a
 network server can use a task for each connection, and still only use, say,
 64 bytes per connection if that's possible instead of the number of stack
 pages that got allocated for previous computation (assuming an extreme
 version that allocates a stack segment on every call).

 However, there is another approach that can replace segmented stacks for
 that purpose, namely having the compiler automatically transform blocking
 functions to instead return a future (with limited lifetime).

 This means that segmented allocation only happens for functions that
 indirectly perform I/O and only allocates the exact amount of memory needed
 to retain state that must persistent across the blocking I/O operation,
 while other functions execute normally using traditional stacks.

 The simplest example of this feature is async/await in C# 5, and Scala has
 a delimited continuation passing transformation that can be used to do the
 same thing.

 Has this been considered for Rust?


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Mozilla hiring a research engineer to work on Rust

2013-10-24 Thread David Piepgrass
 Mozilla is going to hire another engineer to work on Rust! As we head
 toward Rust 1.0 we are looking for a motivated individual with serious
 chops to help us grind through the remaining blocking bugs. Enthusiasm
 for Servo will also be looked upon with great favor. See all the gory
 details here: https://careers.mozilla.org/en-US/position/oMiEXfwp

 I was a bit shocked to receive this rejection after just 2 hours and 15
minutes:

Thank you for taking the time to apply at Mozilla. We are always looking
for help creating great software and appreciate your offer to work with
us!
Unfortunately, we're not always able to find a match within our
organization
for everyone's skills and experience. After reviewing your application we
did not find a fit at this time, and as a result will not be able to move
forward
further.

If you don't want to give a reason, that's you're perogative, I guess, but
this message doesn't even acknowledge that I applied for a *specific*
position. I don't believe in 2 hours and 15 minutes someone actually
checked if I was eligible for each of the available openings, not that I'm
interested in most of the other positions anyhow.

Also, I would at least like to know that the Rust team itself rejected me
and not some generic HR person.

Also, if you are looking for ways to help build a better internet, there
is no
easier way than running Firefox Aurora as your daily browser and filing
bugs and/or sending us your feedback.

Getting hired by Mozilla could have changed my life. So this is a bit of a
tacky way to finish the rejection, don't you think?
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Unified function/method call syntax and further simplification

2013-10-19 Thread David Piepgrass

  This is meant as a followup to an earlier thread[1] on the subject and
 the
  related ticket[2].
 
  [1]: http://thread.gmane.org/gmane.comp.lang.rust.devel/2622/
  [2]: https://github.com/mozilla/rust/issues/6974
 
  The idea in those earlier discussions is that methods could also be
 called
  using function syntax, supplying `self` as the first argument, so instead
  of `self_arg.method(arg)`, you could write `method(self_arg, arg)`. I'm
  wondering if this could be taken a couple steps further to simplify the
  whole story regarding functions, methods, traits, and impls. The idea is
  that the distiction between functions and methods would be erased almost
  completely, and methods (now being just functions) would be imported
  explicitly.
 
  It would involve the following pieces:
 
   - If the first argument of a top-level `fn` is named `self`, it can be
  called using method syntax. So if you have `fn foo(self: MyType, n: int)
  { .. }` at the top level, you can write `object_of_my_type.foo(123)`. You
  can also still call it using function syntax: `foo(object_of_my_type,
 123)`.
 

 I see no reason for the restriction of self. Why not simply say that any
 function can be called with first_arg.func(...) style ?


D has that rule (which they call UFCS), and I find it confusing
sometimes. When a function is declared with function syntax and it makes
sense or feels right that it should be a function, my mind is not
expecting to see method syntax and I may have trouble figuring out later
what an apparent method call refers to, even if I've seen the function
declaration. Mind you it is worse in D than Rust, because in D, function
declarations can be hidden inside what they call eponymous templates,
which has stumped me in the past.

In any case, wouldn't it help narrow down searches if you could search for
fn foo(self instead of only fn foo? (again though, Rust is not as bad
for searching as the C-family languages that have no fn keyword.) In C#
it's nice that I can find all the so-called extension methods by searching
for (this .
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] real-time programming? usability?

2013-10-18 Thread David Piepgrass
* Use postfix syntax for pointer dereference, like in Pascal:
   (~rect).area() becomes  rect~.area() . That reads left-to-right
  with nary a precedence mistake.
 
  While Rust?s auto-dereference feature and type checker will
  sometimes catch that mistake, it's better to just fix the failure
  mode. All security holes in the field got past the type checker
  and unit tests.
 

 Do you realise that `~rect` means create an owned box [a pointer] that
 contains `rect` and isn't not a dereference in Rust? (That is performed
 by `*rect`.)


I would add that if pointer dereference were a suffix operator, it would
have to be changed from * to (e.g.) ~. Why? Because if foo* means
dereference foo then it becomes ambiguous whether foo * - bar means
(foo*)-bar dereference foo and subtract bar or foo*(-bar) multiply foo
by negated bar. Due to this ambiguity, it is difficult for a language to
simultaneously have

1. Operators that can be prefix or infix, and
2. Operators that can be infix or suffix.

To avoid the ambiguity, one can introduce an operator like ~ that is prefix
or suffix but never infix.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Structural enums for datasort refinements

2013-09-04 Thread David Piepgrass
On Wed, Aug 28, 2013 at 11:19 AM, David Piepgrass qwertie...@gmail.comwrote:


 From: Bill Myers bill_my...@outlook.com

 I was reading a proposal about adding datasort refinements to make enum
 variants first-class types, and it seems to me there is a simpler and more
 effective way of solving the problem.

 The idea is that if A, B and C are types, then A | B | C is a
 structural enum type that can be either A, B or C.

 ...


 Hi, I'm just your friendly everyday lurker... Assuming there's nothing in
 this proposal that fundamentally breaks the language, I just wanted to say
 I think this idea is fantastic. You almost don't need Some(T) since
 OptionT could just be None|T.

 I would add that I recall recently some people were discussing how to do a
 variant type in Rust. If all struct types in a program are assigned a
 unique tag, this very same feature could support a variant type, which is
 defined as the union of all types. Then any struct converts implicitly to
 variant (oh, and since I just wrote a parser generator that supports
 inverted sets like ~('a'..'z'), it occurs to me that the type system could
 readily support any type except A | B as well.)

 The tag could either be a unique integer index, or a pointer to a global
 variable that contains type information (the latter, it seems to me,
 automatically solves the dynamic linking problem how do we ensure two
 unrelated DLLs have unique tags? DLL loaders already support relocation in
 case of conflicts.)

 Oops, I just remembered that Rust implements enum types using a fixed-size
memory area that is as large as the largest possible item. So a variant (or
anything except) type, having unlimited size, doesn't directly fit into
that model.

But the compiler could switch to a heap representation for variants. Or,
better, variants could use a smart fixed-size representation in which heap
allocation is used only when the variant is storing a larger type. For
instance, a variant could always use two words, one word for the type tag
and one word for the value. If the current data type T is one word or
smaller, it is stored directly in the second word. Otherwise, the second
word is a ~T pointer.

Just an idea.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Structural enums for datasort refinements

2013-08-28 Thread David Piepgrass
 From: Bill Myers bill_my...@outlook.com

 I was reading a proposal about adding datasort refinements to make enum
 variants first-class types, and it seems to me there is a simpler and more
 effective way of solving the problem.

 The idea is that if A, B and C are types, then A | B | C is a
 structural enum type that can be either A, B or C.

 In addition, A can be implicitly converted to A | B, A | B can be
 implicitly converted to A | B | C, and also (A | B) | C and A | (B |
 C) are equivalent to A | B | C, and finally C | B | A is equivalent to
 A | B | C (to support the latter, the implementation needs to sort
 variants in some arbitrary total order before assigning tag numbers).

 Furthermore, a way to bind variables to an or pattern is introduced to
 allow to convert A | B | C to A | B in the case that it holds an A or a
 B.

 This way, one can rewrite Option as a type alias like this:
 struct SomeT(T);
 struct None;

 type OptionT = None | SomeT;

 Which is like the current Option, but also makes None and SomeT
 first-class types.

 The current enum syntax can remain as syntax sugar for the above code.


Hi, I'm just your friendly everyday lurker... Assuming there's nothing in
this proposal that fundamentally breaks the language, I just wanted to say
I think this idea is fantastic. You almost don't need Some(T) since
OptionT could just be None|T.

I would add that I recall recently some people were discussing how to do a
variant type in Rust. If all struct types in a program are assigned a
unique tag, this very same feature could support a variant type, which is
defined as the union of all types. Then any struct converts implicitly to
variant (oh, and since I just wrote a parser generator that supports
inverted sets like ~('a'..'z'), it occurs to me that the type system could
readily support any type except A | B as well.)

The tag could either be a unique integer index, or a pointer to a global
variable that contains type information (the latter, it seems to me,
automatically solves the dynamic linking problem how do we ensure two
unrelated DLLs have unique tags? DLL loaders already support relocation in
case of conflicts.)


The only issue I see is what to do for code such as let mut x = Some(3);
 x = None;: with this proposal, Some and None are separate unrelated types,
 so we either have this code emit an error, or x must be given the type
 Someint | None automatically, which however can lead to obscure error
 messages if one mistakenly attempts to assign a string to it causing the
 type to become Someint | None | ~str (i.e. the user might be told than
 a match is not exhaustive because it does not handle the ~str case,
 rather than that they assigned a ~str to an Option-typed variable).

 It should be possible to allow this, and make the error-emitting code use
 heuristics to figure out whether it is more likely that the user assigned a
 value of the wrong type, or used an enum improperly (for example, by
 looking at whether the implicitly created enum type is ever written
 explicitly in the source, and whether the deduced structural enum type is
 being used in places that require a non-enum type).

 Alternatively, one can stipulate that only types that are structs, or that
 are structs marked enum struct or case struct or similar can become
 part of an inferred structural enum, but this seems unappealing.


To keep the feature more conservative it's not unreasonable to (initially,
at least) restrict the members of the union to be struct types; any
non-struct type can still be used with Some(T). But the restriction doesn't
entirely solve this particular problem; yeah, the compiler will complain if
you assign ~str to a variable intended to be an Option, but it still won't
complain if you assign some struct type to it.


 Note that some structural enums can change representations depending
 generic instantiation, since T | int becomes just int if T = int, while
 it is ~str | int if T = ~str (and similar for SomeT | Someint), but
 this should not be a problem.

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Can Rust allow a bitwise equality test?

2013-07-18 Thread David Piepgrass
  I think at the least we should offer a #[deriving(Basics)] for use on
 public
  types so that people aren't forced to memorize Eq Ord TotalOrd TotalEq
  IterBytes Clone (unless we can find a silly SFINAE-esque acronym...
  http://www.wordsmith.org/anagram/anagram.cgi?anagram=eottic ).

 Plenty of types can't actually be ordered, and in *many* cases not all
 fields should be considered for equality/ordering and they may or may
 not be listed in the order the comparison should try.

 The only two that rarely require any extra consideration are
 `Clone`/`DeepClone`, since they should be on almost every type without
 a destructor.


I just had a random thought.

I once implemented a data structure for .NET called a VList (
http://www.codeproject.com/Articles/26171/VList-data-structures-in-C) which
provided a SmartSelect pseudo-LINQ method. If you had a list of numbers,
you could ensure they are all positive like this:

list.SmartSelect(x = Math.Max(x, 1))

The reason it's called SmartSelect is that it returns a changed list only
if the select operation *changes* any of the values (and even then it may
still be able to re-use the tail of the list). The tricky part is detecting
when there has been any changes. Ideally I would have liked to simply do a
bitwise equality test because it would be very fast and requires no special
support from the data type, but .NET doesn't have a bitwise equality test.
So I ended up having to use a test that always requires dynamic method
invocation, which I have heard is fantastically slow in the general case of
structs that don't implement IEquatableT.

I wonder if Rust could, in the general case, allow my bitwise equality
test. I realize that bitwise equality isn't real equality, but in this
case it's good enough. For instance if the selector changes -0.0 to +0.0,
which is value-equal but bitwise-different, the effect is fairly
harmless--a partially new list is allocated instead of re-using the old
list.

Of course, if the list contains references (~T, @T), the bitwise test
should compare the references themselves, without dereferencing.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] rustdoc rewrite and redesign

2013-06-21 Thread David Piepgrass
 It might be worth looking into how .NET or other platforms with similar
 architecture accomplish this, if at all.

The C# compiler has a switch that converts C# XML doc comments into an XML
file, which is placed in the output folder beside the .DLL or .EXE file.
This starting point makes a lot of sense, as binaries can be distributed
with their documentation, and IDE intellisense can show basic
documentation directly from the XML file, which is found automatically by
looking for an XML file beside each referenced DLL. (Creating
pretty-printed HTML documentation from the XML gets a bit complicated; a
remarkably large number of separate tools are involved, but these tools are
bundled together, and thanks to IDE features, the plain XML gets a lot of
mileage.)

While creating XML, the compiler resolves short references like see
cref=Foo/ into a complete reference like see cref=M:Blah.Blah.Foo/
(where M means Method, T means Type, etc.)

-- 
- David
http://loyc-etc.blogspot.com
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] bikeshed on closure syntax

2012-04-17 Thread David Piepgrass

  This requires arbitrary lookahead to disambiguate from tuples.

 This bit in particular. Really really don't want to cross the bridge to
 arbitrary lookahead in the grammar.


Pardon me, but I'm not convinced that there is a problem in lambdas
like (x, y) - (x + y). By analogy, you can realize that ((x * y) + z, q)
is a tuple instead of a simple parenthesized expression when you reach the
comma -- you don't need to look ahead for a comma in advance. So why not
treat (x, y) as a tuple until you reach the - and then reinterpret the
contents at that point? This works as long as the syntax of a lambda
argument list is a subset of the tuple syntax, anyway. If that's not the
case, parsing gets messier, though I'm sure arbitrary lookahead is not be
the only possible implementation.
-- 
- David
http://loyc-etc.blogspot.com
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev