Re: [rust-dev] mutable vs. functional APIs

2013-10-21 Thread Erick Tryzelaar
In my opinion, there are two main reasons why one would prefer an immutable
API over a mutable one: aliasing and sharing substructures. Given that
unique pointers and references have mostly solved the first one, in my
opinion we should prefer mutable APIs unless the API is going to take
advantage of structure sharing. I don't think it makes a lot of sense to
have immutable APIs like this:

fn frob(mut self) { ... }
fn frobed(self) - Frob { let x = self.clone(); x.frob(); x }

It's a lot more straightforward for the users to write `let y = x.clone();
y.frob();`, and it protects us from another combinatorial explosion of
methods.

All that being said, I feel there is an open question on whether or not to
prefer statement oriented mutable APIs (methods like `fn frob(mut self)`)
and chain-oriented APIs (methods like `fn frob(self) - Frob`). Does anyone
have a good argument for one over the other?



On Sat, Oct 19, 2013 at 9:42 AM, Eric Sampson eric.samp...@gmail.comwrote:


 Date: Fri, 18 Oct 2013 10:54:23 -0700
 From: Jeff Petkau j...@google.com




 On my code (disclaimer: only toy projects to learn Rust so far),  I've
 been
 pretty happy with a mut_ prefix for mutable versions.

   newthing = oldthing.push(foo)
   anything.mut_push(foo)

   x = bagofun.sort()
   bagosadness.mut_sort()

   etc.

 Advantages:
 - consistent meaning with the 'mut' keyword.
 - works with pretty much any name.
 - makes mutable versions just a bit uglier than immutable code.

 Disadvantages:
 - If an API is inherently mutable, it gets pretty noisy.
 - A bit ugly, probably turns off newcomers.
 - If the compiler warns on ignoring return values, and mutating methods
 return (), then a convention might be unnecessary.

 --Jeff


 What about establishing a convention that mutable methods start with an
 uppercase letter while non-mutating methods start with a lowercase letter?
 It would be lightweight in terms of character count/looks and at the same
 time give mutable methods a slight visual emphasis, which makes sense I
 think.

 I know this convention is already used by Traits, but when I looked
 through some code with the above proposal in mind it would be easy to
 distinguish between these two uses of the same convention due to the
 differing contexts they're used in.

 -Eric






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


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


Re: [rust-dev] mutable vs. functional APIs

2013-10-21 Thread Brendan Zabarauskas
 chain-oriented APIs (methods like `fn frob(self) - Frob`)


What about:

~~~
fn frob(self) - Frob {
let mut x = self;// not sure if you need `cast::transmute_mut` here
x.thing = foo();
x
}
~~~

That would solve the 'copying' problem.

I was actually considering doing this as a way of initialising an object in a 
fluent style:

~~~
let perlin = Perlin::from_seed_str(Kittens)
.with_frequency(2.0)
.with_octaves(3);
~~~

~Brendan

On 22/10/2013, at 9:18 AM, Erick Tryzelaar erick.tryzel...@gmail.com wrote:

 In my opinion, there are two main reasons why one would prefer an immutable 
 API over a mutable one: aliasing and sharing substructures. Given that unique 
 pointers and references have mostly solved the first one, in my opinion we 
 should prefer mutable APIs unless the API is going to take advantage of 
 structure sharing. I don't think it makes a lot of sense to have immutable 
 APIs like this:
 
 fn frob(mut self) { ... }
 fn frobed(self) - Frob { let x = self.clone(); x.frob(); x }
 
 It's a lot more straightforward for the users to write `let y = x.clone(); 
 y.frob();`, and it protects us from another combinatorial explosion of 
 methods.
 
 All that being said, I feel there is an open question on whether or not to 
 prefer statement oriented mutable APIs (methods like `fn frob(mut self)`) 
 and chain-oriented APIs (methods like `fn frob(self) - Frob`). Does anyone 
 have a good argument for one over the other?
 
 
 
 On Sat, Oct 19, 2013 at 9:42 AM, Eric Sampson eric.samp...@gmail.com wrote:
 
 Date: Fri, 18 Oct 2013 10:54:23 -0700
 From: Jeff Petkau j...@google.com
 
 
 
 
 On my code (disclaimer: only toy projects to learn Rust so far),  I've been
 pretty happy with a mut_ prefix for mutable versions.
 
   newthing = oldthing.push(foo)
   anything.mut_push(foo)
 
   x = bagofun.sort()
   bagosadness.mut_sort()
 
   etc.
 
 Advantages:
 - consistent meaning with the 'mut' keyword.
 - works with pretty much any name.
 - makes mutable versions just a bit uglier than immutable code.
 
 Disadvantages:
 - If an API is inherently mutable, it gets pretty noisy.
 - A bit ugly, probably turns off newcomers.
 - If the compiler warns on ignoring return values, and mutating methods
 return (), then a convention might be unnecessary.
 
 --Jeff
 
 
 What about establishing a convention that mutable methods start with an 
 uppercase letter while non-mutating methods start with a lowercase letter? It 
 would be lightweight in terms of character count/looks and at the same time 
 give mutable methods a slight visual emphasis, which makes sense I think. 
 
 I know this convention is already used by Traits, but when I looked through 
 some code with the above proposal in mind it would be easy to distinguish 
 between these two uses of the same convention due to the differing contexts 
 they're used in.
 
 -Eric
 
 
 
 
  
 
 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev
 
 
 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev

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


Re: [rust-dev] mutable vs. functional APIs

2013-10-21 Thread Erick Tryzelaar
On Mon, Oct 21, 2013 at 4:10 PM, Brendan Zabarauskas bjz...@yahoo.com.auwrote:

 chain-oriented APIs (methods like `fn frob(self) - Frob`)


 What about:

 ~~~
 fn frob(self) - Frob {
 let mut x = self;// not sure if you need `cast::transmute_mut` here
 x.thing = foo();
 x
 }
 ~~~



You don't need the `transmute_mut` here, doing `let mut x = self;` works
just fine.



 That would solve the 'copying' problem.

 I was actually considering doing this as a way of initialising an object
 in a fluent style:

 ~~~
 let perlin = Perlin::from_seed_str(Kittens)
 .with_frequency(2.0)
 .with_octaves(3);
 ~~~


I agree, it's great for initialization, I've used this approach too for
https://github.com/erickt/rust-elasticsearch for building up JSON objects.
I could see some logic to us using chaining by default. It has some nice
symmetry with the iterator protocol:

```
fn frob(xs: ~[int]) - ~[int] {
xs
.push(0)
.push(1)
.push(2)
.move_iter().map(|x| x + 1).collect()
}
```
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] mutable vs. functional APIs

2013-10-19 Thread Eric Sampson
 Date: Fri, 18 Oct 2013 10:54:23 -0700
 From: Jeff Petkau j...@google.com



 On my code (disclaimer: only toy projects to learn Rust so far),  I've been
 pretty happy with a mut_ prefix for mutable versions.

   newthing = oldthing.push(foo)
   anything.mut_push(foo)

   x = bagofun.sort()
   bagosadness.mut_sort()

   etc.

 Advantages:
 - consistent meaning with the 'mut' keyword.
 - works with pretty much any name.
 - makes mutable versions just a bit uglier than immutable code.

 Disadvantages:
 - If an API is inherently mutable, it gets pretty noisy.
 - A bit ugly, probably turns off newcomers.
 - If the compiler warns on ignoring return values, and mutating methods
 return (), then a convention might be unnecessary.

 --Jeff


What about establishing a convention that mutable methods start with an
uppercase letter while non-mutating methods start with a lowercase letter?
It would be lightweight in terms of character count/looks and at the same
time give mutable methods a slight visual emphasis, which makes sense I
think.

I know this convention is already used by Traits, but when I looked through
some code with the above proposal in mind it would be easy to distinguish
between these two uses of the same convention due to the differing contexts
they're used in.

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


Re: [rust-dev] mutable vs. functional APIs

2013-10-18 Thread Kevin Ballard
The new Path API still has a return a new path set of APIs. They're just 
named differently. For example, the old path.push(foo) is now 
path.join(foo). And all the path.set_*() mutating methods have variants 
path.with_*() that return a new path.

-Kevin

On Oct 18, 2013, at 9:09 AM, Jack Moffitt j...@metajack.im wrote:

 In the latest Rust upgrade for Servo, I noticed that the path API is
 now mutate-in-place instead of return a new path. It used to be that
 path.push(foo) gave you a new path with an extra component, but now
 path.push(foo) returns () and mutates the path in place.
 
 I liked the old API better. I realize this is probably more consistent
 with std::vec, and consistency is good. I thought I'd bring this up to
 see what other people thought as a lot of the APIs are getting
 rewritten lately and I haven't seen any concrete guidelines on what
 they should be.
 
 If we decide that both API styles are good to have, what should the
 naming convention be for the functional vs. mutable ones? Ruby,
 Scheme, and Clojure use `!` to denote the in-place mutation ones, but
 that syntax is for macros in rust.
 
 jack.
 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev



smime.p7s
Description: S/MIME cryptographic signature
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] mutable vs. functional APIs

2013-10-18 Thread Daniel Micay
On Fri, Oct 18, 2013 at 12:09 PM, Jack Moffitt j...@metajack.im wrote:

 In the latest Rust upgrade for Servo, I noticed that the path API is
 now mutate-in-place instead of return a new path. It used to be that
 path.push(foo) gave you a new path with an extra component, but now
 path.push(foo) returns () and mutates the path in place.

 I liked the old API better. I realize this is probably more consistent
 with std::vec, and consistency is good. I thought I'd bring this up to
 see what other people thought as a lot of the APIs are getting
 rewritten lately and I haven't seen any concrete guidelines on what
 they should be.

 If we decide that both API styles are good to have, what should the
 naming convention be for the functional vs. mutable ones? Ruby,
 Scheme, and Clojure use `!` to denote the in-place mutation ones, but
 that syntax is for macros in rust.

 jack.


I think an immutable version should only be exposed if it's as efficient as
operating in-place. For containers, I really don't want to have APIs that
exist only to make allocating a whole new container and copying over more
convenient. It's harder to write efficient code when inefficient code looks
more idiomatic.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] mutable vs. functional APIs

2013-10-18 Thread Kevin Ballard
On Oct 18, 2013, at 11:14 AM, Daniel Micay danielmi...@gmail.com wrote:

 On Fri, Oct 18, 2013 at 12:09 PM, Jack Moffitt j...@metajack.im wrote:
 In the latest Rust upgrade for Servo, I noticed that the path API is
 now mutate-in-place instead of return a new path. It used to be that
 path.push(foo) gave you a new path with an extra component, but now
 path.push(foo) returns () and mutates the path in place.
 
 I liked the old API better. I realize this is probably more consistent
 with std::vec, and consistency is good. I thought I'd bring this up to
 see what other people thought as a lot of the APIs are getting
 rewritten lately and I haven't seen any concrete guidelines on what
 they should be.
 
 If we decide that both API styles are good to have, what should the
 naming convention be for the functional vs. mutable ones? Ruby,
 Scheme, and Clojure use `!` to denote the in-place mutation ones, but
 that syntax is for macros in rust.
 
 jack.
 
 I think an immutable version should only be exposed if it's as efficient as 
 operating in-place. For containers, I really don't want to have APIs that 
 exist only to make allocating a whole new container and copying over more 
 convenient. It's harder to write efficient code when inefficient code looks 
 more idiomatic.

I agree wholeheartedly with this. Path needed to preserve the convenient 
“functional update” methods, because creating new paths based on existing 
immutable ones is rather common. But the APIs are definitely not more 
convenient than the mutation ones, just as convenient.

Regarding Jeff’s suggestion for a mut_ prefix, that really only makes sense to 
me when returning some form of mut value. Although that would typically be 
.as_mut_foo() rather than .mut_foo(). In general, I think method names should 
make it reasonably obvious whether it’s mutating or not without having to use 
“mut_”. In the case of Path, the name .push() has a long history of mutating 
the receiver, so Path.push() mutates.

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


Re: [rust-dev] mutable vs. functional APIs

2013-10-18 Thread Brian Anderson

On 10/18/2013 11:14 AM, Daniel Micay wrote:
On Fri, Oct 18, 2013 at 12:09 PM, Jack Moffitt j...@metajack.im 
mailto:j...@metajack.im wrote:


In the latest Rust upgrade for Servo, I noticed that the path API is
now mutate-in-place instead of return a new path. It used to be that
path.push(foo) gave you a new path with an extra component, but now
path.push(foo) returns () and mutates the path in place.

I liked the old API better. I realize this is probably more consistent
with std::vec, and consistency is good. I thought I'd bring this up to
see what other people thought as a lot of the APIs are getting
rewritten lately and I haven't seen any concrete guidelines on what
they should be.

If we decide that both API styles are good to have, what should the
naming convention be for the functional vs. mutable ones? Ruby,
Scheme, and Clojure use `!` to denote the in-place mutation ones, but
that syntax is for macros in rust.

jack.


I think an immutable version should only be exposed if it's as 
efficient as operating in-place. For containers, I really don't want 
to have APIs that exist only to make allocating a whole new container 
and copying over more convenient. It's harder to write efficient code 
when inefficient code looks more idiomatic.


Efficiency isn't the only design consideration and not always the most 
important, even in Rust. I imagine that path manipulation is not a 
performance bottleneck for most applications.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] mutable vs. functional APIs

2013-10-18 Thread Gábor Lehel
On Fri, Oct 18, 2013 at 6:09 PM, Jack Moffitt j...@metajack.im wrote:

 If we decide that both API styles are good to have, what should the
 naming convention be for the functional vs. mutable ones? Ruby,
 Scheme, and Clojure use `!` to denote the in-place mutation ones, but
 that syntax is for macros in rust.


FWIW, the convention in many other APIs is that the return-modified-copy
versions use past participle. So e.g. the modify-in-place method would be
called `foo.frobulate()`, while the functional one would be called
`foo.frobulated()`. I think this is nice, but it can get a bit more
difficult with arguments. (If the mutating method is called
`foo.append(bar)`, what's the other one? `foo.appended(bar)`?
`foo.with_appended(bar)`? Something else?)

-- 
Your ship was destroyed in a monadic eruption.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] mutable vs. functional APIs

2013-10-18 Thread Steve Klabnik
To be clear, '!' doesn't mean mutation, it means 'dangerous.' For example,
some methods return nil on error, and the bang version throws an excption
on error.

Sometimes, mutation is dangerous, though... ;)
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev