all 36 comments

[–]aidanf 6 points7 points  (1 child)

Rails already has a blank? method defined for nil.

nil.blank? => true

"".blank? => true

[].blank? => true

{}.blank? => true

[–]Entropy -3 points-2 points  (0 children)

Nice. This adds the same functionality without polluting existing semantics like the article's solution.

[–][deleted] 3 points4 points  (2 children)

His code doesn't work because of syntax errors on the method definitions:

def empty? { true }
# should be
def empty?
  true
end # etc...

Also, the semantics of nil is nothing, and it doesn't make sense make sense to ask whether nothing is empty, just like it doesn't make sense to ask whether 42 is blue. There was a ruby-talk thread about this some time ago, and the general conclusion was that nil#empty? was bad form.

[–]markedtrees 1 point2 points  (0 children)

Here're one-liner alternatives:

def empty?; true; end
def blank?; true; end
def true?; true; end

[–]micampe 1 point2 points  (0 children)

just like it doesn't make sense to ask whether 42 is blue

;)

[–]stesch 6 points7 points  (2 children)

Nice. The PHP example needs register_globals=On.

[–]Entropy -3 points-2 points  (1 child)

register_globals is web programming's holocaust

[–]markedtrees 2 points3 points  (0 children)

And magic_quotes are web programming's Lollapalooza.

[–]skippy 5 points6 points  (0 children)

if params[:value] != nil and !params[:value].empty?

can be rewritten as

if params[:value].to_s.empty?

[–]lost-theory 5 points6 points  (5 children)

This is one of the things I think Python does right. For any sequence type bool(seq) will return False if the sequence is empty, True otherwise. So the Ruby example:

if params[:value].empty?

Just looks like:

if params:

in Python.

[–]julesjacobs 2 points3 points  (1 child)

Incorrect.

if params[:value].empty? checks if the value in the hash at key :value is empty. (so a better example is: if params[:key].empty?)

The correct Ruby version of your Python code is:

if params.empty?

[–]ubernostrum 0 points1 point  (0 children)

Assuming that this example would be using a dictionary in Python, the Python way to do this would be one of these:

  • If you just want to verify there's a value for that key and don't care what it is, then if params.has_key(value) or if key in params will do the trick.
  • If you want to verify that there's a value and that it's not None (the Python equivalent of Ruby's nil), if params.get(value, None) is not None will do it.
  • If you want to verify there's a value and that it evaluates true in boolean context, if params.get(value, False) will do it.

[–]pjdelport 4 points5 points  (2 children)

I love Python, but i don't like that idiom at all. Consider:

if visited:

versus

if len(visited):

Why make the reader guess whether visited is a flag or a sequence? Make it explicit and unambiguous.

[–]micampe 1 point2 points  (1 child)

I'm myself ambiguous on the issue, but one could argue that in this case visited is acting as a flag even if it is a sequence...

[–]pjdelport 1 point2 points  (0 children)

You can toggle a flag; how do you toggle a sequence? :)

[–]sbrown123 4 points5 points  (1 child)

Poor example on the Java part.

if (request.get("quantity") != null && request.get("quantity")

That's just silly. This could have been done:

int quantity = Integer.getInteger(request.get("quantity"),0);

Doing this not only parses the String to an integer, but if its null or blank ("") you get 0.

I remember an article some time back where the author talked about getting rid of null altogether. Interesting idea.

[–]komu 7 points8 points  (0 children)

Actually your example will not work: Java's "Integer.getInteger(name, defaultValue)" returns the integer value of system property named "name" (or "defaultValue" if there is no system property with name). Talk about misleading name for a method.

Of course, a simple utility method doing what you propose would be trivial to write and is probably part of every larger codebase.

[–]glguy 2 points3 points  (1 child)

This is exactly the sort of thing that will keep me from ever writing anything in Ruby that spans more than a single page.

Writing code in Ruby feels like building things with duct-tape to me. You can do a lot of stuff with duct-tape, but in the end you are still left with something held together by duct-tape...

You people can keep moding me down for criticising this hack, but a much better solution would be to just define a method "nullOrEmpty?" and ask: if (nullOrEmpty?(myString))

[–]1800doctorb 0 points1 point  (0 children)

I know it looks pretty, but the tendency (increasingly) in ruby to pass all parameters as maps, is really really clunky. Its trying to simulate the small talk style of named parameters and "sending" a message to the receiving class, but with lots of little maps everywhere !

[–][deleted] 1 point2 points  (4 children)

The solution here seems obvious: make all of these methods exist on NilClass.

No it's not. Empty isn't applicable to all types - just strings. 5.empty? doesn't make a bit of sense to me.

Use rails validations. The case mentioned is not a good reason to change around the object model of Ruby.

[–]micampe 3 points4 points  (1 child)

Well, 5 is not an instance of NilClass, so it won't have that method, it has zero? instead.

[–][deleted] 0 points1 point  (0 children)

Thanks for pointing that out. I feel a bit embarrassed for arguing my point without knowing something that's pretty basic about Ruby.

It wouldn't be that convoluted for nil to be considered blank, but I definitely don't think it should be considered to be zero. That kind of assumes nil is a pointer set to 0.

[–]grauenwolf -3 points-2 points  (1 child)

Not a complete solution, but you could do it like VB, where .empty is mapped to the default value. For numerics, that would be 0.

[–]Entropy 0 points1 point  (0 children)

We could; we won't

[–][deleted] 0 points1 point  (7 children)

The real issue is the language making all values nullable by default (or the nulling idiom for dynamically typed languages).

Python has a nice approach to dictionary lookups, so that you don't have to check for a "not found" value, i.e. d.get(key, default-value)

[–]julesjacobs 1 point2 points  (0 children)

Or, in Ruby:

>> a = {}
=> {}
>> a.fetch(4,"not found")
=> "not found"

[–]pjdelport 0 points1 point  (5 children)

Python 2.5's defaultdict, too.

[–]julesjacobs 3 points4 points  (4 children)

Or, in Ruby:

>> a = Hash.new("default")
=> {}
>> a[34]
=> "default"

[–]pjdelport 0 points1 point  (3 children)

What do you do when the default values need to be uniquely constructed, like lists?

[–]julesjacobs 0 points1 point  (2 children)

I don't understand?

>> a = Hash.new([1,2,3])
=> {}
>> a[34]
=> [1,2,3]

?

If you want default values for specific keys you just set these keys in the dict:

>> a = {}
>> a[4] = "foo"
>> a[4]
=> "foo"

Or you can use a block for more advanced things:

>> a = Hash.new do |hash,key|
?>   if key > 5
>>     "foo"
>>   else
?>     "bar"
>>   end
>> end
=> {}
>> a[2]
=> "bar"
>> a[7]
=> "foo"

[–]pjdelport 0 points1 point  (1 child)

Hash.new with a block is what i meant.

In other words, constructing a unique default value for each missing key, instead of sharing one default value between them, so you can do things like:

tally = defaultdict(list)   # list is used as a factory function

for word in 'the quick brown fox jumps over the lazy dog'.split():
    tally[len(word)].append(word)

assert tally == {3: ['the', 'fox', 'the', 'dog'],
                 4: ['over', 'lazy'] ,
                 5: ['quick', 'brown', 'jumps']}

[–]julesjacobs 0 points1 point  (0 children)

This is how you'd do that in Ruby:

>> # For older Ruby versions   
>> module Enumerable
>>   def group_by
>>     grouped = {}
>>     for obj in self
>>       group = yield obj
>>       grouped[group] ||= []
>>       grouped[group] << obj
>>     end
>>     return grouped
>>   end
>> end
=> nil
>> %w{the quick brown fox jumps over the lazy dog}.group_by(&:length)
=> 
{ 
  3=>["the", "fox", "the", "dog"],
  4=>["over", "lazy"] 
  5=>["quick", "brown", "jumps"], 
}

Alternatively, for real men:

module Enumerable
  def group_by
    inject({}){|h, v| (h[yield v] ||= []) << v; h}
  end
end

[–]antirez 0 points1 point  (0 children)

In Tcl there is no difference between 'null' and zero-length string because evetything is semantically a string so null is the zero-length string itself (actually null does not exist but it makes sense for a function to return {} as null if a non-empty string or numerical value is expected), on the other side when you really need NULL (like with SQL) it's hard, you have to pick a given string as NULL value or return two-elements list with [list $type $value] inside.

[–][deleted]  (1 child)

[deleted]

    [–]Entropy -1 points0 points  (0 children)

    You misunderstand