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

How would these be any shorter in Python or Ruby?

  @GET
  public Collection<Integer> listStudentIds() {
    return STUDENTS.keySet();
  }
or

  @DELETE
  @Path("{uid: [0-9]+}")
  public boolean deleteStudent(@PathParam("uid") int uid) {
    final Student deletedStudent = STUDENTS.remove(uid);

    if (deletedStudent == null) {
      throw new WebApplicationException(Response.Status.NOT_FOUND);
    } else {
      return true;
    }
  }
I'll grant that Java programs often become more verbose than their Python/Ruby counterparts - but I would argue that trait can be held to a minimum with the proper libraries and coding style.


First example, Python (keeping a similar API):

    list_student_ids = get(STUDENTS.keys) # [0]
second example, Python:

    @delete
    @path(r'{uid: [0-9]+}')
    def delete_student(uid):
        if STUDENTS.pop(uid, None): # [0]
            return True
        raise WebApplicationException(Response.Status.NOT_FOUND)
the last line generally wouldn't be this complex, in Flask you'd just call `flask.abort(404)` (which can be used inline with an `or`, as with waffle_ss's ruby example, but that's not usual/good Python style), in Django it'd be `raise Http404()`.

Although in Django you'd really use the `get_object_or_404` shortcut for ORM objects:

    def delete_student(uid):
        get_object_or_404(StudentModel, pk=uid).delete()
        return True
And you wouldn't bother with the return since a 200 result would mean the deletion was correctly executed.

[0] Used Python's MutableMapping API here, it works slightly differently than Java's equivalent Map interface: `.keys()` returns a sequence of the mapping's keys and `.pop()` asks for a default value to return in case nothing was found there, otherwise it raises `KeyError` if the key was not found)


An other note: the @path decorator would probably use named groups instead of some sort of DSL, so

    r'(?P<uid>[0-9]+)'
(the `r` prefix is for `r`awstring, so the developer does not have to string-escape each backslash used in the regex among other things)


In Ruby, everything evaluates to true except false and nil. Also, the last statement executed is your return value. Therefore your first function could be written as

  def delete_student(uid)
    STUDENTS.remove(uid) || raise WebApplicationException.new(Response.Status.NOT_FOUND)
  end


I have no idea what the annotations mean, but if we use exceptions for transmitting error conditions, then there is no point having a true | exception function.

    public void deleteStudent(int uid) {
      if (STUDENTS.remove(uid) == null) {
        throw new WebApplicationException(Response.Status.NOT_FOUND);
      }
    }


I love it!

And that is the reason I still write in Python or Lisp when I don't need something (Hadoop, Lucene, etc) from the JVM ;-)


If you need something from the JVM and want to write Lisp, use Clojure. Checkout Hadoop extensions in Clojure at https://github.com/jblomo/oddjob .


In that case it is preferable to use "or" over "||" since then you do not have to worry so much about operator precedence because "or" has about the weakest of all operators. This means in this case that you can skip the explicit ".new" for the exception.

  def delete_student(uid)
    STUDENTS.remove(uid) or raise WebApplicationException, Response.Status.NOT_FOUND
  end


I seem to remember this same feature causing lots of headache in C in the form of subtle bugs mostly the result of this being used in awkward ways.

Personally I'd rather have a distinct boolean value to test for, the java version is much more explicit as to exactly what its doing.


Hmm can't say I've ever encountered something like that in Ruby so far. However, if you want a strict boolean it's pretty easy to get:

  !!STUDENTS.remove(uid)


In Ruby, you don't write code, code writes you! ;-)


You could make it shorter by using something like sinatra[1]. Here is my pseudo-sinatra code.

  get "/list_student_ids" do
    STUDENTS.key_set
  end

  delete "/delete_student/:uid" do
    STUDENTS.remove(params[:uid]) or raise WebApplicationException, Response::Status::NOT_FOUND
    true
  end
1. http://www.sinatrarb.com/


Your savings here are mainly from removing types. That's another matter entirely.


1. Thing's most of those types provide no value in being spelled out like that. The ones on the methods have documentary advantages, but that's about it, the rest is magical invocations to make a stupid compiler happy.

2. There's also a gain from the framework being able to map things to each other without being told explicitly. `@PathParam("uid")` for instance, it's only there because the framework has no way to match the parameter name `uid` to the URL-extracted parameter `uid`. Likewise with HTTP methods being part of the routing instead of a separate annotation, in part.

3. Java's APIs and type system, such as implicit nulls and not being able to use arbitrary types in boolean contexts


I would say they are mainly from removing the need for decorators due to there being a nice lambda function/block syntax. So we can define methods like "get" and "delete" which does the job of the decorators, creating something kind of like a mini-DSL.

Some savings through the removal of types, sure, but that is not what I personally see as most import here.


With Ruby folks can always try to remove redundancy. :-)

I find it amazing that "DRY" has become such a positive pattern when it was touted as one of the driving points of the Ruby on Rails framework. Don't repeat yourself.

For instance, Java folks are always ready to throw exceptions instead of letting stuff resolve itself if it doesn't quite work.


In that example I only throw an exception when you try to delete a student who doesn't exist. The reason I do so is that it contains semantic information which is useful for the client.

If I returned a fake value - the client would get a 200 response on his attempt to delete a non-existent resource, which is clearly the incorrect behavior. I could return nothing - but then the client would see a 204. So, I choose to throw an exception with a response 'NOT_FOUND'

  throw new WebApplicationException(Response.Status.NOT_FOUND);
so that the client gets a 404 response.


I did try and build your code to run the test (I've no idea where the CsvParam and DateParam classes come from) but I think that the following will give you what you want without throwing the exception.

  @DELETE
  @Path("{uid: [0-9]+}")
  public Response deleteStudent(@PathParam("uid") int uid) {
    final Student deletedStudent = STUDENTS.remove(uid);

    if (deletedStudent == null) {
      return Response.status(Response.Status.NOT_FOUND).build();
    } else {
      return Response.ok().entity(true).build();
    }
  }


Ah, I see what you mean - thanks!

The full (buildable) source code - including the CsvParam and DateParam classes - are here: https://github.com/smanek/students


Yes, this is only an example.

There are a few things I'd like to point out to add to this example:

1) JAX-RS is still new. In the future, they might improve the exception handling or whatnot (so if you return null, they might decided to return 404 ... who knows)

2) We can always wrap all JAX-RS with a Filter. So you can throw JPA level exception (not found) and let the filter catch it and convert it to WebApplicationException(404). Thus in theory, your JAX-RS implementation won't have any RuntimeException explicitly in the code.




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

Search: