A nicer syntax for generic extension methods

I have been trying to figure out how to Rubify generic extension methods
for
use with the likes of Rx, Open XML SDK, etc. Ivan went over it a bit
with me
this weekend, but I’m still having difficulty including a module within
a
.NET type. Is that even possible?

Given:
names = System::Collections::Generic::List.of(System::String).new
names.add ‘Ryan’

Current syntax:
greetings =
System::Linq::Enumerable.method(:select).of(System::String).call
{ |name| “Howdy, #{name}” }

compare with greetings = names.map { |name| “Howdy, #{name}” }

Desired syntax:
greetings = names.linq_select { |name| “Howdy, #{name}” }

Granted, you might make a case for using the Ruby Enumerable methods
over
Linq, but when it comes to using other libraries, the more Ruby-like
syntax
would be preferred. In the interest of working out the preferred syntax,
I
thought using System.Linq.Enumerable would be easiest.

Ivan provided the following:

module EnumerableExtensions

def included(base)
if base.respond_to? :to_clr_type
@klass = base.to_clr_type
end
end

def linq_select(&b)
System::Linq::Enumerable.method(:select).of(@klass).call &b
end

end

The questions I’m not able to answer are:

  1. Can I somehow open up a .NET class, say
    System::Collections::Generic::List[T] and include the
    EnumerableExtensions?
    So far, I’m finding that’s a no.
  2. How do I hook in the included(base) method above? I’m assuming
    that’s
    a one-time call, but I don’t see anywhere that it’s called when a
    module is
    included. Do I need to use a before_filter or perform that action at
    the
    beginning of the linq_select method?

Thanks!

Ryan R.

Email: [email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

IIRC you can open “concrete” generics, but not “open” ones: In plain
english
this means you can add methods to List but not List.

This is essentially because List isn’t a real type in the CLR, it’s
basically some metadata that can be used to build a real type when the T
is
supplied.

You could as an alternative add methods to the underlying non-generic
IEnumerable interface, but then you’d have to do some run-time
reflection to
figure out that your List is actually a List… This is probably
not
nice.

In theory when CLR4 lands and has support for co/contra variant
generics,
List should match List and everything else, but I don’t
know
if IronRuby would also work for this?

Good luck

If you index System.Collections.Generic.List by a fixnum instead of a
class/module you’ll get the generic definition of arity 1

Nice! I had no idea that feature existed

Actually, you can add Ruby methods to List … IronRuby type system
does some magic for you :):

include System::Collections::Generic
=> Object
List[Fixnum].included_modules
=> [System::Collections::Generic::List[T],
System::Collections::Generic::IList[Fixnum],
System::Collections::Generic::IList[T],
System::Collections::Generic::ICollection[Fixnum],
System::Collections::Generic::ICollection[T],
System::Collections::Generic::IEnumerable[Fixnum],
System::Collections::Generic::IEnumerable[T],
System::Collections::IEnumerable, Enumerable,
System::Collections::IList, System::Collections::ICollection,
System::Collections::Generic, Kernel]

As you can see the List<> generic type definition is treated as a module
that is mixed in each of its instantiations. Although there are no
predefined methods on it you can open it and add some. First we need to
get Ruby class for List. If you index System.Collections.Generic.List
by a fixnum instead of a class/module you’ll get the generic definition
of arity 1. Let’s name it ListOfT:

ListOfT = List[1]

And then we can open it up:

module ListOfT
… def size
… count
… end
… end
=> nil
l = List[Fixnum].new
=> []
l.add(1)
=> nil
l.add(2)
=> nil
l.size
=> 2

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Orion E.
Sent: Monday, February 01, 2010 6:31 PM
To: [email protected]
Subject: Re: [Ironruby-core] A nicer syntax for generic extension
methods

IIRC you can open “concrete” generics, but not “open” ones: In plain
english this means you can add methods to List but not List.

This is essentially because List isn’t a real type in the CLR, it’s
basically some metadata that can be used to build a real type when the T
is supplied.

You could as an alternative add methods to the underlying non-generic
IEnumerable interface, but then you’d have to do some run-time
reflection to figure out that your List is actually a List…
This is probably not nice.

In theory when CLR4 lands and has support for co/contra variant
generics, List should match List and everything else,
but I don’t know if IronRuby would also work for this?

Good luck
On Tue, Feb 2, 2010 at 7:52 AM, Ryan R.
<[email protected]mailto:[email protected]> wrote:
I have been trying to figure out how to Rubify generic extension methods
for use with the likes of Rx, Open XML SDK, etc. Ivan went over it a bit
with me this weekend, but I’m still having difficulty including a module
within a .NET type. Is that even possible?

The questions I’m not able to answer are:

  1. Can I somehow open up a .NET class, say
    System::Collections::Generic::List[T] and include the
    EnumerableExtensions? So far, I’m finding that’s a no.
  2. How do I hook in the included(base) method above? I’m assuming
    that’s a one-time call, but I don’t see anywhere that it’s called when a
    module is included. Do I need to use a before_filter or perform that
    action at the beginning of the linq_select method?

Thanks!

Ryan R.

Email: [email protected]mailto:[email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

just pass your block to the constructor of a delegate and you should be
good
to go

Action.new { more_work_here }

Met vriendelijke groeten - Best regards - Salutations
Ivan Porto C.
Blog: http://flanders.co.nz
Twitter: http://twitter.com/casualjim
Author of IronRuby in Action (http://manning.com/carrero)

Thanks, Ivan. That’s awesome … that’s just like F#. I should have
realized
it would be that simple. I’ll post this to the Delegates section of the
.NET
interop page on the wiki, since it currently doesn’t exist.

Also, I noticed you alluded to something similar in IronRuby in Action
where
you talk about LightSpeed, but I couldn’t find anything in the MEAP copy
I
have. If I am able to spin up a few LINQ samples (probably Rx, Pfx,
and/or
XLinq), I’ll shoot them your way, if you are interested.

Cheers!

Ryan R.

Email: [email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

On Tue, Feb 2, 2010 at 11:40 PM, Ivan Porto C. <

That’s fantastic, Tomas, thanks! Is there any way to pass a block,
lambda,
or Proc into the slot for the delegate, or perhaps a way to create a
.NET
delegate (or Expression) from a block, lambda, or Proc?

Thanks,

Ryan R.

Email: [email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

On Tue, Feb 2, 2010 at 1:36 AM, Tomas M.
<[email protected]

I just thought of something else. How do you deal with anonymous types
in
IronRuby? We don’t have the type name when writing the code. Do we have
to
create at least a Ruby type for everything returned from an
Enumerable.Select? I suppose that’s where the module wrapper over LINQ
would
perhaps come in handy?

Ryan R.

Email: [email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

Or is that not even an issue? I suppose if you are writing a LINQ
statement
within IR, you won’t ever create an anonymous type; you would rather
create
a Ruby type, hash, etc. I suppose this would only be an issue if you had
a
method returning an anonymous type, which is already a documented no-no,
so
I will retract my previous question. :slight_smile: Sorry for the brain-dump.

Ryan R.

Email: [email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

Okay, just posted a rough first stab at the topic. This is all generic
delegates, too; I haven’t bothered with plain old generics. :slight_smile: Please
let me
know if you have any feedback. I will add the stuff Tomas noted above
when I
get a chance a little later.

http://ironruby.net/Documentation/.NET/Delegates
http://ironruby.net/Documentation/.NET/Delegates
Ryan R.

Email: [email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

On Wed, Feb 3, 2010 at 10:49 AM, Ivan Porto C. <
[email protected]> wrote:

that may be wrong but it’s close to something like that…

I like that syntax. It reminds me of F#'s computation expressions. I was
thinking something more along the lines of what
arelhttp://m.onkey.org/2010/1/22/active-record-query-interface?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+monkeyonrails+(m.onkey+on+rails)is
doing.

Ryan

For lightspeed I wrote an internal dsl that allows you to query
similarly to
the regular api but no special module for linq stuff. I skipped linq
altogether didn’t need it there.

so what I created there is (It’s in the asp.net mvc chapter btw)

find_all User do
where a(:name).like(“ivan%”) & a(:age) > 23
order_by :name.desc
end

that may be wrong but it’s close to something like that…

Met vriendelijke groeten - Best regards - Salutations
Ivan Porto C.
Blog: http://flanders.co.nz
Twitter: http://twitter.com/casualjim
Author of IronRuby in Action (http://manning.com/carrero)

Will that be 1.0 or after?

Ryan R.

On Wed, Feb 3, 2010 at 11:12 AM, Tomas M. <

The LINQ experience should get better as soon as we improve our
interaction with the type inference engine in DLR overload resolver.
IronRuby currently doesn’t use its full power like IronPython does, so
you need to explicitly specify more generic arguments that should be
necessary.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Ivan Porto
Carrero
Sent: Wednesday, February 03, 2010 8:49 AM
To: [email protected]
Subject: Re: [Ironruby-core] A nicer syntax for generic extension
methods

For lightspeed I wrote an internal dsl that allows you to query
similarly to the regular api but no special module for linq stuff. I
skipped linq altogether didn’t need it there.

so what I created there is (It’s in the asp.nethttp://asp.net mvc
chapter btw)

find_all User do
where a(:name).like(“ivan%”) & a(:age) > 23
order_by :name.desc
end

that may be wrong but it’s close to something like that…

Met vriendelijke groeten - Best regards - Salutations
Ivan Porto C.
Blog: http://flanders.co.nz
Twitter: http://twitter.com/casualjim
Author of IronRuby in Action (http://manning.com/carrero)

On Wed, Feb 3, 2010 at 4:01 PM, Ryan R.
<[email protected]mailto:[email protected]> wrote:
Thanks, Ivan. That’s awesome … that’s just like F#. I should have
realized it would be that simple. I’ll post this to the Delegates
section of the .NET interop page on the wiki, since it currently doesn’t
exist.

Also, I noticed you alluded to something similar in IronRuby in Action
where you talk about LightSpeed, but I couldn’t find anything in the
MEAP copy I have. If I am able to spin up a few LINQ samples (probably
Rx, Pfx, and/or XLinq), I’ll shoot them your way, if you are interested.

Cheers!

Ryan R.

Email: [email protected]mailto:[email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

On Tue, Feb 2, 2010 at 11:40 PM, Ivan Porto C.
<[email protected]mailto:[email protected]>
wrote:
just pass your block to the constructor of a delegate and you should be
good to go

Action.new { more_work_here }

Met vriendelijke groeten - Best regards - Salutations
Ivan Porto C.
Blog: http://flanders.co.nz
Twitter: http://twitter.com/casualjim
Author of IronRuby in Action (http://manning.com/carrero)

On Tue, Feb 2, 2010 at 11:38 PM, Ryan R.
<[email protected]mailto:[email protected]> wrote:
That’s fantastic, Tomas, thanks! Is there any way to pass a block,
lambda, or Proc into the slot for the delegate, or perhaps a way to
create a .NET delegate (or Expression) from a block, lambda, or Proc?

Thanks,

Ryan R.

Email: [email protected]mailto:[email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/

On Tue, Feb 2, 2010 at 1:36 AM, Tomas M.
<[email protected]mailto:[email protected]>
wrote:
Actually, you can add Ruby methods to List … IronRuby type system
does some magic for you ☺:

include System::Collections::Generic
=> Object
List[Fixnum].included_modules
=> [System::Collections::Generic::List[T],
System::Collections::Generic::IList[Fixnum],
System::Collections::Generic::IList[T],
System::Collections::Generic::ICollection[Fixnum],
System::Collections::Generic::ICollection[T],
System::Collections::Generic::IEnumerable[Fixnum],
System::Collections::Generic::IEnumerable[T],
System::Collections::IEnumerable, Enumerable,
System::Collections::IList, System::Collections::ICollection,
System::Collections::Generic, Kernel]

As you can see the List<> generic type definition is treated as a module
that is mixed in each of its instantiations. Although there are no
predefined methods on it you can open it and add some. First we need to
get Ruby class for List. If you index System.Collections.Generic.List
by a fixnum instead of a class/module you’ll get the generic definition
of arity 1. Let’s name it ListOfT:

ListOfT = List[1]

And then we can open it up:

module ListOfT
… def size
… count
… end
… end
=> nil
l = List[Fixnum].new
=> []
l.add(1)
=> nil
l.add(2)
=> nil
l.size
=> 2

Tomas

From:
[email protected]mailto:[email protected]
[mailto:[email protected]mailto:[email protected]]
On Behalf Of Orion E.
Sent: Monday, February 01, 2010 6:31 PM
To: [email protected]mailto:[email protected]
Subject: Re: [Ironruby-core] A nicer syntax for generic extension
methods

IIRC you can open “concrete” generics, but not “open” ones: In plain
english this means you can add methods to List but not List.

This is essentially because List isn’t a real type in the CLR, it’s
basically some metadata that can be used to build a real type when the T
is supplied.

You could as an alternative add methods to the underlying non-generic
IEnumerable interface, but then you’d have to do some run-time
reflection to figure out that your List is actually a List…
This is probably not nice.

In theory when CLR4 lands and has support for co/contra variant
generics, List should match List and everything else,
but I don’t know if IronRuby would also work for this?

Good luck
On Tue, Feb 2, 2010 at 7:52 AM, Ryan R.
<[email protected]mailto:[email protected]> wrote:
I have been trying to figure out how to Rubify generic extension methods
for use with the likes of Rx, Open XML SDK, etc. Ivan went over it a bit
with me this weekend, but I’m still having difficulty including a module
within a .NET type. Is that even possible?

The questions I’m not able to answer are:

  1. Can I somehow open up a .NET class, say
    System::Collections::Generic::List[T] and include the
    EnumerableExtensions? So far, I’m finding that’s a no.
  2. How do I hook in the included(base) method above? I’m assuming
    that’s a one-time call, but I don’t see anywhere that it’s called when a
    module is included. Do I need to use a before_filter or perform that
    action at the beginning of the linq_select method?

Thanks!

Ryan R.

Email: [email protected]mailto:[email protected]
LinkedIn: http://www.linkedin.com/in/ryanriley
Blog: http://wizardsofsmart.net/
Twitter: @panesofglass
Website: http://panesofglass.org/


Ironruby-core mailing list
[email protected]mailto:[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core


Ironruby-core mailing list
[email protected]mailto:[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core


Ironruby-core mailing list
[email protected]mailto:[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core


Ironruby-core mailing list
[email protected]mailto:[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core


Ironruby-core mailing list
[email protected]mailto:[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core

On Wed, Feb 3, 2010 at 10:59 AM, Ivan Porto C. <
[email protected]> wrote:

hashes?

Just an example, though perhaps not the best. :slight_smile:

but may i ask why you’re so hell-bent on linq?

I mostly want some way to use the Reactive Extensions for asynchronous
programming and OpenXML SDK for working with Office docs. In particular,
I’m
thinking of working with IR on top of other C# and/or F# libraries which
might be using one or both of those libraries. If I were to write it in
all
Ruby, I’d probably look at eventmachine for an event loop processor.

I’m definitely open to other solutions.

Linq is a really bad match to ruby with the expressions. it would require
some significant amount of work to get that to work correctly. AFAIK there
is no way in IronRuby to build expressions except use the raw API, but
nothing is in there yet that makes this easier to do.

L2S uses expressions, but I don’t think everything uses them. If all
that’s
required is a delegate, that’s not so hard and can be be accomplished
with a
wrapping Ruby method that accepts a block and wraps the block into a
Func to
pass into the LINQ method. Given some of the previous posts, I think
creating a general module to wrap these methods shouldn’t be too
difficult.
Thoughts?

Anyway you can reuse anonymous types did you know that? Alex James
learnt

the trick from Wes Dyer

Meta-Me | Microsoft Learn

Yeah, I knew about that, but I don’t really want to touch casting by
example
in Ruby. It might not be bad, but why bother when I can use something
from
Ruby?

Ryan

hashes?

but may i ask why you’re so hell-bent on linq? Linq is a really bad
match
to ruby with the expressions. it would require some significant amount
of
work to get that to work correctly. AFAIK there is no way in IronRuby
to
build expressions except use the raw API, but nothing is in there yet
that
makes this easier to do.

Anyway you can reuse anonymous types did you know that? Alex James
learnt
the trick from Wes Dyer


Met vriendelijke groeten - Best regards - Salutations
Ivan Porto C.
Blog: http://flanders.co.nz
Twitter: http://twitter.com/casualjim
Author of IronRuby in Action (http://manning.com/carrero)

This might help, there’s a library in the VS directory
samples/CSharpSamples.zip/LinqSamples/DynamicQuery take a look, under
the
covers it’s creating expressions LINQ Expressions.

In C# you will just chain methods like:
myCollection.Where(“property=myValue”).OrderBy(“anotherProp desc”);

I think this library could be extended to “easily” create any type of
expression in IR. This could be useful to consume existing libraries
that
already expect an expression.