DEV Community

Discussion on: Share a code snippet in any programming language and describe what's going on

Collapse
 
ben profile image
Ben Halpern

I'll go first with Ruby

class String
  def like_a_cow
   "Moo #{self} mooooo"
  end
end

"Hello".like_a_cow
=> "Moo Hello mooooo"
Enter fullscreen mode Exit fullscreen mode

Classes in Ruby can be easily modified. The above code adds the like_a_cow method to String... So now the whole program can make a string "moo", like above.

Collapse
 
jmfayard profile image
Jean-Michel πŸ•΅πŸ»β€β™‚οΈ Fayard • Edited
fun String.likeACow() = "Moo $this mooo"
Enter fullscreen mode Exit fullscreen mode

Same thing in Kotlin, super handy.

EDIT: A big advantage with for example the JavaScript version monkey-patching String.prototype, is that the String class is not modified everywhere in your codebase.

It works like a normal function, you import the new function only if and where you need it. See kotlinlang.org/docs/extensions.htm...

Collapse
 
darkwiiplayer profile image
π’ŽWii πŸ³οΈβ€βš§οΈ

Nice example, but I think it could be refined somewhat

using (Module.new do
  refine String do
    def like_a_duck
      "#{self} quack quack"
    end
  end
end)

puts "Hello".like_a_duck
Enter fullscreen mode Exit fullscreen mode
Collapse
 
leopfeiffer profile image
Leo Pfeiffer

Similar in Scala:

extension(str: String) {
  def like_a_cow = s"Moo ${str} mooooo"
}

scala> "Hello".like_a_cow
val res0: String = Moo Hello mooooo
Enter fullscreen mode Exit fullscreen mode
Collapse
 
silverhairs profile image
Boris Kayi • Edited

In Dart it's

extension on String{
 String get like_a_cow => 'Moo $this mooooo';
}

"Hello".like_a_cow;
=> "Moo Hello mooooo"
Enter fullscreen mode Exit fullscreen mode
Collapse
 
maxart2501 profile image
Massimo Artizzu

In JavaScript it's:

String.prototype.like_a_cow = function() {
  return `Moo ${this} mooooo`;
};
"Hello".like_a_cow()
> "Moo Hello mooooo"
Enter fullscreen mode Exit fullscreen mode

I wonder how many languages allow this?

Collapse
 
kenbellows profile image
Ken Bellows

I'll do you one better: if you define a dynamic getter using Object.defineProperty, you can make it look exactly like the Ruby example:

Object.defineProperty(String.prototype, 'likeACow', {
    get() {
        return `Moo ${this} mooooo`
    }
})

'Hello'.likeACow
> 'Moo Hello mooooo'
Enter fullscreen mode Exit fullscreen mode
Collapse
 
arjunsahlot profile image
Arjun

Python:

class str(str):
    def like_a_cow(self):
        return f"Moo {self} mooooo"

str("Hello").like_a_cow()
> "Moo Hello mooooo"
Enter fullscreen mode Exit fullscreen mode

I should add that this is not good practice. str is a built in function and you should not override it.

Collapse
 
ryencode profile image
Ryan Brown • Edited

C# allows this,


    public static class StringExtension
    {
        public static string LikeACow(this string self)
        {
            return $"Moo {self} mooooo";
        }
    }
Enter fullscreen mode Exit fullscreen mode

you can now use this as

Console.WriteLine("Hello".LikeACow());
Enter fullscreen mode Exit fullscreen mode

I use extensions a lot on sealed library classes to add Quality Of Life things. One example is creating cleaner methods for adding parameters to SQLClient ClientCommand objects as one liners instead of multi-command monstrosities. (ok, they aren't that big, but do look unclean)

Thread Thread
 
lionelrowe profile image
lionel-rowe

I think it's different (safer) in C# though, right? Like you need to add using <namespace> for the new methods to be accessible. So it's not true monkey patching, which is generally dangerous and best avoided.

Thread Thread
 
ryencode profile image
Ryan Brown

Indeed you would need to use the containing namespace. And are likely safer as it would be pretty hard to modify the behaviour of code outside of your intended changes. (I think you would have to try very hard to have any affect outside of your explicit calls to the extension methods)

I won't claim to know much about TRUE monkey patching, but wikipedia's Extension Methods and Monkey Patching articles do reference each other in suggestive ways. ;)

Collapse
 
sanzstez profile image
Alexandr Stets

It is bad practice to do such things. Better use

module Extensions
  refine String do
    def like_a_cow
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

and add in you class

use Extensions
Enter fullscreen mode Exit fullscreen mode
Collapse
 
maowtm profile image
maowtm

In Rust you can add functions to other types with traits. This actually adds the like_a_cow function for all types that are printable, including strings. You have to use the trait though.

pub trait LikeACow {
    fn like_a_cow(&self) -> String;
}

impl<T: std::fmt::Display> LikeACow for T {
    fn like_a_cow(&self) -> String {
        format!("Moo {} mooooo", &self)
    }
}

fn main() {
    // need to `use LikeACow;` if used in other modules, but not here.
    let s = "hello";
    println!("{}", s.like_a_cow());
}
Enter fullscreen mode Exit fullscreen mode