Can an initialize method fail?

I may be doing this wrong. :slight_smile: In some languages, I
might do something like:
user = User.new(name, password)

If the User class is unable to initialize a corresponding
user, it might not produce a valid User object.

What is a good way to do something like this? It seems that I could
do it by having User#initialize throw an exception, but my intuition
is that “user got password wrong” is not exactly an exceptional
circumstance;
I have been told exceptions should be used only for unusual cases, and
should not be part of the fairly normal usage of a program.

My assumption that a “User” should be one who is logged in may not
be strictly necessary, but I rather like the way it simplifies
everything
else – this way, only one or two lines of code ever have to consider
the possibility of a user who didn’t authenticate successfully.

So far as I can tell, though, the initialize method’s return is
politely ignored. So. I perceive 4 options:

  1. Throw an exception from User#initialize if the name and password
    are invalid.
  2. Add some kind of check immediately after this call which
    verifies a successful login, and otherwise sets the local variable
    user to nil.
  3. Add a User#valid method or something similar, and check it all
    over.
  4. Ask ruby-talk, because surely I’m missing something obvious.

(Sorry about the stupid newbie questions; I promise to ask smart
questions
once I’ve gotten better at this.)

-s

Peter S. wrote:

I have been told exceptions should be used only for unusual cases, and
should not be part of the fairly normal usage of a program.

My assumption that a “User” should be one who is logged in may not
be strictly necessary, but I rather like the way it simplifies everything
else – this way, only one or two lines of code ever have to consider
the possibility of a user who didn’t authenticate successfully.

So far as I can tell, though, the initialize method’s return is
politely ignored.

I’d use a different class method, like User.login, or some such. Then
you can return either a valid User instance or nil as required. If you
want to completely avoid exceptions, you’ll either need to have a
#valid? method in the instance, or actually do the credential validation
at the class level (which seems slightly wrong to me, but there you go).
It might look a little like this:

class User
def User.login(name, password)
u = User.new(name, password)
return u.valid? ? u : nil
end
end

or:

class User
def User.login(name, password)
can_log_in_with(name, password) ? User.new(name) : nil
end

def User.can_log_in_with(name, password)
# do the name and password validation outside a User object here
end
end

Of course, if you do go this route, you’ll need to make sure that you
never call User.new directly, and popping an exception under those
circumstances is, I think, justified.

In message [email protected], Alex Y. writes:

I’d use a different class method, like User.login, or some such. Then
you can return either a valid User instance or nil as required. If you
want to completely avoid exceptions, you’ll either need to have a
#valid? method in the instance, or actually do the credential validation
at the class level (which seems slightly wrong to me, but there you go).

Oh, that might be a good choice. Might even be a good case for one
of those factory methods. :slight_smile: Hadn’t thought of that, but I like it.
That might simplify some logic elsewhere.

-s

On 27.05.2007 10:37, Peter S. wrote:

In message [email protected], Alex Y. writes:

I’d use a different class method, like User.login, or some such. Then
you can return either a valid User instance or nil as required. If you
want to completely avoid exceptions, you’ll either need to have a
#valid? method in the instance, or actually do the credential validation
at the class level (which seems slightly wrong to me, but there you go).

Oh, that might be a good choice. Might even be a good case for one
of those factory methods. :slight_smile: Hadn’t thought of that, but I like it.
That might simplify some logic elsewhere.

I’d like to take that a bit further. I see two major aspects here:
“initialization” and “login”. “Initialization” of course includes
creating an instance of class User and probably also fetching its state
from some persistent location (file, database). Ideally this is done by
some persistence framework.

“Login” is an application level concept. A user logs into an
application. Part of this is creation of some form of session as a
result of a successful login (be it a GUI object or some form of web
application session). An important part of the login process is
verification of the credentials the human user provides.

Now it depends on your application and how you model this. For example,
your class User might be purely model or application aware. Both have
their pros and cons (“model” is more flexible and has cleaner separation
of concerns, “application” might be easier and less code).

One “clean separation” solution would be to have a class User with a
method #password_ok? or something that accepts whatever the human user
provides and returns a boolean result indicating that the credentials
were ok or not. Instantiation is probably done via querying some form
of persistence framework (e.g. db_session.query_user(:login=>“pseeb”).
#login is probably a method in some application class that combines
fetching the user and then verifying the password.

Of course there’s a ton of ways to implement that. But IMHO it’s useful
to make oneself aware of all the aspects involved here. Also it made a
nice example of the kinds of reasonings I like to apply to those cases.
:slight_smile:

Kind regards

robert