Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm not sure I understand this. Is RubyMotion just a set of wrappers around Objective-C classes to allow you to develop applications in Ruby? If so, why? Is the point to allow Rubyists that don't want to learn Objective-C to develop applications in Ruby?


RubyMotion is not a wrapper. It is an implementation of Ruby on the Obj-C runtime. This means that a RubyMotion object is an Obj-C object (for comparison, a Ruby object in MRI is just a C struct). So why would you want to use RubyMotion? Well...

* Obj-C, from the very start, was implemented as a strict superset of C. This means that every valid bit of C code must also be valid Obj-C. This places some rather sever limitations on the Obj-C syntax. Ruby does not have this limitation, and neither does RubyMotion. So one reason you might use RubyMotion is to get a cleaner syntax that does the same thing as Obj-C.

* The Obj-C runtime is very dynamic. You can create classes on the fly, add methods to them at runtime, move methods around between objects, and create methods dynamically. The Obj-C language makes it nearly impossible to take advantage of any of these features of the Obj-C runtime. So another reason you might use RubyMotion is to get the most out of the Obj-C runtime.


In Objective-C we can create methods, properties and classes on the fly using <objc/runtime.h>

Here's how to create a property on the fly (great for categories)

@dynamic progressView;

- (void)setProgressView:(ACProgressView )progressView { objc_setAssociatedObject(self, ACProgressViewKey, progressView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }

- (ACProgressView )progressView { return objc_getAssociatedObject(self, ACProgressViewKey); }


You still had to tell the compiler ahead of time about the property. The actual test is more like

    NSObject obj = [NSObject init];
    giveObjectAProperty(obj, @"progressView");
    obj.progressView = [NSNumber 42];
Writing giveObjectAProperty may not be "nearly impossible" but it sure isn't easy.

And of course the parent is talking about methods, not properties, but...same argument.


Fair enough.

Here's how you'd make that class on the fly:

   Class mySubclass = objc_allocateClassPair([NSObject class], "MySubclass", 0);
Here's how you'd add a description method to a newly created class:

   static NSString *Description(id self, SEL _cmd){
        return [NSString stringWithFormat: @"<%@ %p: foo=%@>",[self class], self, [self foo]];
   }

    // add Description to mySubclass
    // grab NSObject's description signature so we can borrow it
    Method description = class_getInstanceMethod([NSObject class],
                                                 @selector(description));
    const char *types = method_getTypeEncoding(description);
    
    // now add
    class_addMethod(mySubclass, @selector(description), (IMP)Description, types);
And your iVars:

   class_addIvar(mySubclass, "foo", sizeof(id), rint(log2(sizeof(id))), @encode(id));


What jballanc is saying is that yes these things are possible in Objective-C, but the technique of doing these tricks in Ruby/Motion is an order of magnitude simpler and idiomatic:

    klass = Object.const_set "MySubclass", Class.new(Object)
    
    klass.send(:attr_accessor, :foo)
 
    klass.send(:define_method, "description") {
      "<#{self.class}: foo=#{self.foo}>"
    }


That was really informative. Thanks for the breakdown.


There are a few very well-written wrappers that make utilizing the Obj-C runtime much easier. MAObjCRuntime [1] is a good example of such a wrapper. Look at MACollectionUtilities [2] as an example of how to use MAObjCRuntime.

[1]: https://github.com/mikeash/MAObjCRuntime [2]: https://github.com/mikeash/MACollectionUtilities


Bullet #2 is so very very wrong. Nice try. I can't speak to the first bullet.


Please elaborate; I have only minimal experience with ObjC and do not use Ruby in the context of native development, so any well-described counterpoints would be much appreciated.

Edit: I obv. didn't write your parent comment. What I meant was that I'm sure others in my position, having read your parent, would appreciate more elaboration from you as well. :)


Sorry, you're right. It was an off the cuff rebuttal with no substance. Added to the parent comment.


I think he meant ruby in bullet 2


I'm doing a serious project in RubyMotion at the moment. It doesn't save you having to know Objective-C, since all example code for doing anything in Cocoa are still in Objective-C, but it does save you from having to write in Objective-C itself. That means, no writing everything twice (header files, type declarations), and no brackets. I find Ruby a lot more readable, even when writing the incredibly long method names from Cocoa.

But the real payoff is threefold:

1) You can use and write very ruby-ish wrappers for things. A great example is teacup, which lets you essentially write stylesheets for your UIViews (and I guess now NSViews).

2) Working with collections like arrays and hashes is MUCH more convenient. You can spend a good part of your time doing just that.

3) Command-line toolchain. It's not for everyone, of course, but for those who work better like that, it's a revolution.

Right now it's pretty wild west. There's no obvious winner in terms of libraries for the data layer, for example. So taking on an RM project right now either means rolling up your sleeves and hacking on the infrastructure, or just living with raw Cocoa, without benefit of autocomplete. Give it another 6-12 months and I think you'll see a very strong contender.


Your header file is your interface and documentation to anyone using your code/class. Why wouldn't you want to declare your public interface there?

As for readability. Ruby is getting there but currently:

   - (void)employersWithCarrierID:(uint)carrierID withMaxReturnCount:(uint)count;

   [self employersWithCarrierID:123 withMaxReturnCount:10];
is a lot more readable and verbose than

   def employers (id, count)

   employer 123 10


Except in Ruby, you'd just as likely see named arguments too.

`employer carrier_id: 123, max_return_count: 10` is very much valid ruby.


Beyond that, RM has "real" named arguments based on the objective-C core.


  > That means, no writing everything twice (header files,
  > type declarations)

  Your header files can be practically empty if you don't need to show something to outside. Just put your @property'ies into class extension. Even @synthesize no longer needed (most of the time, there are exceptions).

  > Working with collections like arrays and hashes is MUCH
  > more convenient. You can spend a good part of your time
  > doing just that.
With latest versions of XCode it is possible to use foo[5] instead of [foo objectAtIndex:5] and foo[@"bar"] instead of [foo objectForKey:@"bar"]; There are also array and dictionary literals @[…], @{…} and you can also just type @1 to get NSNumber from primitive.


I'm aware of all that, but of course you DO want to show things to the outside, all the time. I also know about the newer syntax, which is awesome the few times I still dip into ObjC, but I'm more thinking of map/each/select/detect/etc. There are builtin methods for doing those, but their sheer verbosity tends to discourage the sort of free and easy chaining that Ruby encourages. (Some might argue that's a benefit. Not me.)

Cocoa is a fantastic system to build on top of. NSDate is MILES better than the Ruby time stuff, for example. NS/UI solid core plus Ruby's flexible syntax and culture of sensible defaults is a marriage made in heaven.


>> I'm aware of all that, but of course you DO want to show things to the outside, all the time.

Well, there's a solid argument to be made in favor of limiting how much internals are exposed to other objects. I personally like keeping my headers as minimal as possible.


To clarify: Ruby has public and private. You can control visibility all you want, you just don't have to use a separate header file.


I found BlockKit [1] to be very useful for any Ruby-like collection methods. BlockKit, as the name says, uses blocks extensively to provide all the most common collection methods one would find in Ruby. Some examples of these methods, taken from the NSArray(BlocksKit) [2] documentation are "each", "apply", "map" & "reduce". There are much more.

[1]: https://github.com/pandamonia/BlocksKit [2]: http://pandamonia.github.io/BlocksKit/Documentation/Categori...


The legacy is RubyCocoa -> MacRuby -> RubyMotion.

RubyCocoa was actually a wrapper, but was very slow. MacRuby's innovation was that it was a Ruby implementation in Obj-C, but it relied on GC and was Mac OS X only. RubyMotion ditched the need for the GC and supports iOS and now Mac OS X.


Thats part of it and you do not have to use Xcode. Some of the gems such as BubbleWrapper also created a really nice syntax.


[deleted]


RubyMine IDE from IntelliJ [1] is a nice part of the tool-chain. It has auto-complete for RubyMotion.

[1] http://www.jetbrains.com/ruby/


I was about to ask about this. RubyMotion seems amazing, but sometimes objective-c is about just opening that auto-complete and seeing what methods are at your disposal.


That is exactly the point.


Agree. Not language but API should be fixed.


Disagree. And that's why we have RubyMotion! :-)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: