Erlang/OTP Forums

Author Message

<  Erlang questions mailing list  ~  Erlang is getting too big

thomasl_erlang at yahoo.c
Posted: Tue Oct 14, 2003 11:14 am Reply with quote
Guest
--- Bengt Kleberg <Bengt.Kleberg_at_ericsson.com> wrote:
> Thomas Lindgren wrote:
> ...deleted
> > Here's another part that could stand cleaning up:
> >
> > - guard syntax 1: "," and ";"
> > - guard syntax 2: "and", "or"
> > (are they there anymore?)
> > - expression syntax 1: "and", "or"
> > - expression syntax 2: "andalso", "orelse"
> >
> > All of them working somewhat differently.
>
> oops. what is the difference between ',' and 'and'?
> and ';' and 'or'? i
> have been using them to mean the same thing.

As I recall, ";" can't be nested inside a guard, while
'or' can.

";" appeared before guard expressions were
generalized, and the implementation at the time seemed
to require this restriction ... but once generalized
guards were worked out, it puzzles me why a new set of
operators was introduced rather than generalizing the
old ones.

> eiffel has 'andalso' and 'orelse'. the only Smile
> people that finds 'and'
> and 'or' strange are the ones that has a c
> background.

My main objections are the added noise from long
names, the limited usefulness of strict and/or, and
the fact that the obvious names are used for the
unobvious version.

And in C you use && anyway Smile (The &-operator
corresponds to 'band' not horrid 'and'.)

> > My modest proposal:
> >
> > - drop is_* guards (unless there is a pressing
> reason
> > to keep them?)
>
> there is no static typing. therefore it helps (me)
> to be able to
> recognise the return value of a function from its
> name. one way of doing
> this is to teach users (by using the concept in
> guards) to call
> functions that return booleans is_*.
>
> moreover, there is a guard float() and a bif
> float(). the bif returns a
> float, not a boolean.
> this (imho) is confusing

If that is a big problem, why not introduce a new
float-making function, rather than a collection of
extra type tests? Seems simpler all-around.

Best,
Thomas


__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com


Post generated using Mail2Forum (http://m2f.sourceforge.net)
thomasl_erlang at yahoo.c
Posted: Tue Oct 14, 2003 11:42 am Reply with quote
Guest
A question on #6 below: shouldn't it be that the guard
_fails_ if a subexpression crashes?

Anyway, a couple of short comments:

1. Do we WANT to unify guards and expressions?
Personally, I think it might be good, but not if the
solution is messier than what it replaces. It's not a
"must have" for me.

2. Assuming that we do:

Another approach to unifying guards with expressions
would be to introduce the appropriate type tests as
BIFs. Apart from float/1, this seems straightforward?

For float/1 used in expressions, change the BIF to a
type test and write a lint-like program to detect (and
maybe rewrite) all occurrences in existing source
code.

(The linker could also direct calls to float/1 in "old
BEAM code" to the float-making BIF, and calls in "new
code" to the float-testing BIF.)

That way, it seems to me we would avoid having an
extra set of tests identical in all but name. Well,
unless I've overlooked something crucial. (Please
don't say 'backwards compatibility' :-)

Best,
Thomas

--- Richard Carlsson <richardc_at_csd.uu.se> wrote:
>
> On Tue, 14 Oct 2003, Bengt Kleberg wrote:
>
> > Thomas Lindgren wrote:
> > ...deleted
> > > Here's another part that could stand cleaning
> up:
> > >
> > > - guard syntax 1: "," and ";"
> > > - guard syntax 2: "and", "or"
> > > (are they there anymore?)
> > > - expression syntax 1: "and", "or"
> > > - expression syntax 2: "andalso", "orelse"
> > >
> > > All of them working somewhat differently.
> >
> > oops. what is the difference between ',' and
> 'and'? and ';' and 'or'? i
> > have been using them to mean the same thing.
> >
> > eiffel has 'andalso' and 'orelse'. the only Smile
> people that finds 'and'
> > and 'or' strange are the ones that has a c
> background.
>
> Perhaps the most complicated part of the Erlang
> language are the clause
> guards. They are a mess, although we've tried to
> clear up a few things.
>
> 1. Guards are comma-separated sequences
> (conjunctions) of "tests",
> i.e., the commas mean logical "and". (So far so
> good.)
>
> 2. Later, it was added that you could have
> alternative lists
> of tests, if you separated them with
> semicolon as in
> "t01, t02, t03; t11, t12, t13; t21, t22, t23
> ->"
> (a disjunction of conjunctions.) So, the
> semicolons mean
> logical "or" in this context. (This addition was
> probably
> one of the less motivated ones. I've never used
> it myself.)
>
> 3. A "test" is either a comparison "X == Y", "X >
> Y" etc, or
> a call to a built-in test function like
> "integer(X)" or
> "float(Y)". (I.e., it is not just any boolean
> expression.)
>
> 4. Guard tests have a separate name space!
> "integer(X)" above
> is not defined outside guards, so you can't
> write:
>
> Bool = (f(X) and integer(Y))
>
> in normal Erlang code - unless you define
> "integer/1"
> yourself. (But you can't override the tests used
> in guards.)
> The test "float(X)" overrides the built-in
> typecast function
> of the same name. You _can_ write the following:
>
> Bool = (f(X) and float(Y))
>
> but you might be surprised when "float(Y)" does
> not return a
> boolean.
>
> 5 The subexpressions of guard tests are "guard
> expressions",
> which are a limited subset of normal
> expressions. Basically:
> variables, constants, operators and calls to a
> subset of the
> "automatically recognized" BIFs are allowed, but
> nothing else.
>
> 6. Guard tests are implicitly "wrapped in a catch",
> so that if
> a subexpression crashes (the tests themselves
> can't crash),
> they quietly evaluate to "true" instead.
> (Thankfully, the
> number of programmers crazy enough to actually
> make use of
> this "feature" is very small. I have not seen it
> used in OTP
> and I would like to have it removed from the
> language.)
>
> 7. The boolean operators "and" and "or" (and "not"
> and "xor")
> have been in Erlang quite a while, but were
> defined to be
> strict, i.e., always evaluate both arguments.
> Furthermore,
> they could originally not be used anywhere in a
> guard(!).
>
> 8. When "and" and "or" were eventually allowed in
> guards, they
> actually got the same semantics (within guards)
> as "," and
> ";" respectively, since guards cannot
> have side effects
> (and thus it does not matter if you use strict
> evaluation or
> not, space/time aside). But there is no point in
> using and/or
> instead of comma and semicolon unless you like
> longer lines.
> Stick to the normal separators. It's just in
> subexpressions
> that you might use and/or/not/xor once in a blue
> moon.
>
> 9. 'andalso' and 'orelse' (the non-strict versions
> of 'and' and
> 'or' can be useful for avoiding deep nesting of
> case
> switches`, and can make the code much more
> concise. For
> example:
>
> case f(X) of
> true -> true;
> false ->
> case g(X) of
> false ->
> case h(X) of
> true -> true;
> fasle -> false
> end;
> true -> false
> end
> end
>
> is equivalent to
>
> f(X) orelse (not g(X) andalso h(X))
>
> Now, how long did it take for you to verify that
> the
> first version really implements the second one?
> What
> happens if you misspell 'true' or 'false'
> somewhere?
> (Personally, I'd have preferred 'and' and 'or'
> to be
> defined as non-strict to begin with.)
>
> And now, for 10,000 dollars*:
>
> What does the following do, if X is a
> floating-point number?
>
> if float(X), (float(X) == true) -> true;
> true -> false
> end
>
> What we've tried to do in the last years is to make
> the differences
> between normal expressions and guards smaller. It's
> not easy, as I hope
> you can see from the above. It was in order to clear
> up the confusion
> with the guard test namespace that we added the
> "is_..." versions of the
> type tests. These have the same definition
> everywhere, and you can even
> call "erlang:is_integer(X)" if you need to. I think
> they are a good
> thing. It is much easier to say to a beginner "Oh,
> 'integer(X)' is
> old-style - avoid that and use 'is_integer(X)'
> instead." instead of
> trying to explain why he can't write 'integer(X)' in
> other places than
> guard tests.
>
> A new book would certainly be in order, if anyone
> could find a
> publisher.
>
> /Richard
>
>
> * Altairian dollars.
>
>
>
> Richard Carlsson (richardc_at_csd.uu.se) (This space
> intentionally left blank.)
>
=== message truncated ===


__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com


Post generated using Mail2Forum (http://m2f.sourceforge.net)
Bengt.Kleberg at ericsson
Posted: Tue Oct 14, 2003 11:51 am Reply with quote
Guest
Thomas Lindgren wrote:
> --- Bengt Kleberg <Bengt.Kleberg_at_ericsson.com> wrote:
>
...deleted
>>
>>oops. what is the difference between ',' and 'and'?
>>and ';' and 'or'? i
>>have been using them to mean the same thing.
>
>
> As I recall, ";" can't be nested inside a guard, while
> 'or' can.
>

thank you.


...deleted
>
>
>>eiffel has 'andalso' and 'orelse'. the only Smile
>>people that finds 'and'
>>and 'or' strange are the ones that has a c
>>background.
>
>
> My main objections are the added noise from long
> names, the limited usefulness of strict and/or, and
> the fact that the obvious names are used for the
> unobvious version.

imho the only people that think it is ''unobvious'' that and/or evaluate
all their ''arguments'' are the ones that has a c background.


...deleted
>>>My modest proposal:
>>>
>>>- drop is_* guards (unless there is a pressing
>>
>>reason
>>
>>>to keep them?)
>>
>>there is no static typing. therefore it helps (me)
>>to be able to
>>recognise the return value of a function from its
>>name. one way of doing
>>this is to teach users (by using the concept in
>>guards) to call
>>functions that return booleans is_*.
>>
>>moreover, there is a guard float() and a bif
>>float(). the bif returns a
>>float, not a boolean.
>>this (imho) is confusing
>
>
> If that is a big problem, why not introduce a new
> float-making function, rather than a collection of
> extra type tests? Seems simpler all-around.

i find it a good thing (tm) that boolean-return-value-functions are
recognisable from their name.


bengt



Post generated using Mail2Forum (http://m2f.sourceforge.net)
richardc at csd.uu.se
Posted: Tue Oct 14, 2003 12:12 pm Reply with quote
Guest
On Tue, 14 Oct 2003, Thomas Lindgren wrote:

> A question on #6 below: shouldn't it be that the guard
> _fails_ if a subexpression crashes?

D'oh! (I need more coffee.) Yes, of course: if a subexpression
crashes, it quietly evaluates to *false*, thus failing the test.

(And may I repeat: Please don't use this for anything!)

> Anyway, a couple of short comments:
>
> 1. Do we WANT to unify guards and expressions?
> Personally, I think it might be good, but not if the
> solution is messier than what it replaces. It's not a
> "must have" for me.

The point, I think, is to try to get nearer to the principle
of least surprise. The way guards were originally defined,
there were lots of surprises in store, once you went beyond
the simple "f(X) when integer(X) -> ..." ones.

> 2. Assuming that we do:
>
> Another approach to unifying guards with expressions
> would be to introduce the appropriate type tests as
> BIFs. Apart from float/1, this seems straightforward?

Well, the "is_..." forms are BIFs, but I assume you mean
to keep the names integer(X) etc. and also introduce them as BIFs.
But since auto-recognized BIFs override local definitions (sic!),
this would probably break a lot of existing code.

/Richard


Richard Carlsson (richardc_at_csd.uu.se) (This space intentionally left blank.)
E-mail: Richard.Carlsson_at_csd.uu.se WWW: http://user.it.uu.se/~richardc/
"Having users is like optimization: the wise course is to delay it."
-- Paul Graham


Post generated using Mail2Forum (http://m2f.sourceforge.net)
thomasl_erlang at yahoo.c
Posted: Tue Oct 14, 2003 2:26 pm Reply with quote
Guest
--- Richard Carlsson <richardc_at_csd.uu.se> wrote:
> > 2. Assuming that we do:
> >
> > Another approach to unifying guards with
> expressions
> > would be to introduce the appropriate type tests
> as
> > BIFs. Apart from float/1, this seems
> straightforward?
>
> Well, the "is_..." forms are BIFs, but I assume you
> mean to keep the names integer(X) etc. and also
> introduce them as BIFs.

Yes.

> But since auto-recognized BIFs override local
> definitions (sic!),
> this would probably break a lot of existing code.

If you mean BIFs that do not need the erlang: prefix,
then the override nowadays goes in the other
direction. (And correctly so, IMO.)

-module(test).
-compile(export_all).

abs(X) when X > 0 ->
X;
abs(X) ->
-X.

1> c(test).
... Warning: defining BIF abs/1

Best,
Thomas



__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com


Post generated using Mail2Forum (http://m2f.sourceforge.net)
dgud at erix.ericsson.se
Posted: Tue Oct 14, 2003 2:40 pm Reply with quote
Guest
Thomas Lindgren writes:
> > But since auto-recognized BIFs override local
> > definitions (sic!),
> > this would probably break a lot of existing code.
>
> If you mean BIFs that do not need the erlang: prefix,
> then the override nowadays goes in the other
> direction. (And correctly so, IMO.)
>

Hmm...

-module(junk).
-compile(export_all).

x(Y) ->
abs(Y).

abs(X) -> sune.

3> c(junk).
./junk.erl:7: Warning: defining BIF abs/1
{ok,junk}
4> junk:x(Cool.
8
5> junk:x(-Cool.
8
6> junk:abs(Cool.


Post generated using Mail2Forum (http://m2f.sourceforge.net)
richardc at csd.uu.se
Posted: Tue Oct 14, 2003 2:41 pm Reply with quote
Guest
On Tue, 14 Oct 2003, Thomas Lindgren wrote:

> > But since auto-recognized BIFs override local
> > definitions (sic!),
> > this would probably break a lot of existing code.
>
> If you mean BIFs that do not need the erlang: prefix,
> then the override nowadays goes in the other
> direction. (And correctly so, IMO.)
>
> -module(test).
> -compile(export_all).
>
> abs(X) when X > 0 ->
> X;
> abs(X) ->
> -X.
>
> 1> c(test).
> ... Warning: defining BIF abs/1

Ah, but that warning only tells you that you have defined
a function called abs/1, which is also the name of an
auto-recognized BIF.

And if you call it from the outside, as in "test:abs(-1)",
your function is called, as you expect.

But if you try to use it for a local call, you get into
trouble, because it is overridden by the BIF:

-module(test).
-export([myabs/1, abs/1]).

myabs(X) ->
abs(X).

abs(X) when X > 0 ->
{abs, X};
abs(X) ->
{abs, -X}.

1> c(test).
./test.erl:7: Warning: defining BIF abs/1
{ok,test}
2> test:abs(1).
{abs,1}
3> test:myabs(1).
1
4>

(And no, the ordering of the functions above does not matter.)

Is this sufficiently confusing?

/Richard



Richard Carlsson (richardc_at_csd.uu.se) (This space intentionally left blank.)
E-mail: Richard.Carlsson_at_csd.uu.se WWW: http://user.it.uu.se/~richardc/
"Having users is like optimization: the wise course is to delay it."
-- Paul Graham


Post generated using Mail2Forum (http://m2f.sourceforge.net)
thomasl_erlang at yahoo.c
Posted: Tue Oct 14, 2003 7:12 pm Reply with quote
Guest
--- Richard Carlsson <richardc_at_csd.uu.se> wrote:
>
>
> On Tue, 14 Oct 2003, Thomas Lindgren wrote:
>
> > > But since auto-recognized BIFs override local
> > > definitions (sic!),
> > > this would probably break a lot of existing
> code.
> >
> > If you mean BIFs that do not need the erlang:
> prefix,
> > then the override nowadays goes in the other
> > direction. (And correctly so, IMO.)
> >
> > -module(test).
> > -compile(export_all).
> >
> > abs(X) when X > 0 ->
> > X;
> > abs(X) ->
> > -X.
> >
> > 1> c(test).
> > ... Warning: defining BIF abs/1
>
> Ah, but that warning only tells you that you have
> defined
> a function called abs/1, which is also the name of
> an
> auto-recognized BIF.
>
> And if you call it from the outside, as in
> "test:abs(-1)",
> your function is called, as you expect.
>
> But if you try to use it for a local call, you get
> into
> trouble, because it is overridden by the BIF:

As the saying goes, I stand corrected. (Thanks also to
Dan G for pointing this out.)

So, um, well, *shouldn't* a local call really go to
the local version too? I think it should.

Again, I would suggest sailing through the transition
period with a linter. E.g., emit warnings or even
errors when finding a call which is ambiguous in this
respect. (The linter probably should do that anyway.)

Best,
Thomas


__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com


Post generated using Mail2Forum (http://m2f.sourceforge.net)
bjarne at cs-lab.org
Posted: Tue Oct 14, 2003 9:28 pm Reply with quote
Guest
> > If a client doesn't want
> > to modify his source he always has the option of not
> > upgrading past the point where a depricated feature is
> > removed.

Not quite true. Perhaps later
versions are much faster so
he likes to use them.

Bjarne




Post generated using Mail2Forum (http://m2f.sourceforge.net)
cyberlync at yahoo.com
Posted: Tue Oct 14, 2003 10:45 pm Reply with quote
Guest
--- Bjarne_D
ok at cs.otago.ac.nz
Posted: Tue Oct 14, 2003 10:49 pm Reply with quote
Guest
Francesco Cesarini <francesco_at_erlang-consulting.com> wrote:
However, less than 5% of programmers end up using LCs, if not
less. People who are struggling to come to term with the rest
of the language don't, as it is yet another thing to take in.
Something they can solve with recursion.

The reason that I like higher order functions and comprehensions
is that they let me *avoid* recursion. Not that I don't like recursion;
I do. But years ago in Prolog I just got *sick* of writing yet another
list traversal; life is too short to keep writing the same code over and
over and over again.

I was originally opposed to the addition of anonymous functions to Erlang
(not that anyone asked my opinion) on the grounds that it made the language
more complicated, they weren't really needed, and it wasn't clear to me
what was supposed to happen when you reloaded a module that defined such
things and one or more of them was already in use.

I was wrong.

Higher order functions and list comprehensions can shorten your code a
*lot*, and clear brief code using well-known names for tarversal patterns
can be easier to read and maintain than stuff using basic language features.

Imagine trying to use Java without `for' and 'while' statements...



Post generated using Mail2Forum (http://m2f.sourceforge.net)
ok at cs.otago.ac.nz
Posted: Wed Oct 15, 2003 1:35 am Reply with quote
Guest
Richard Carlsson <richardc_at_csd.uu.se> wrote:
[that if you define a local function with the same name
= (symbol/arity) as a pervasive built-in, then you get a
warning that says you've redefined it, and you can call
it from the outside, but on the inside you get the built-in].

It seems to me that this is clearly a bug. The warning is useful,
but a direct call to a function with a visible local definition
should _always_ find that local definition, or what are scope rules for?



Post generated using Mail2Forum (http://m2f.sourceforge.net)
richardc at csd.uu.se
Posted: Wed Oct 15, 2003 8:12 am Reply with quote
Guest
On Wed, 15 Oct 2003, Richard A. O'Keefe wrote:

> Richard Carlsson <richardc_at_csd.uu.se> wrote:
> [that if you define a local function with the same name
> = (symbol/arity) as a pervasive built-in, then you get a
> warning that says you've redefined it, and you can call
> it from the outside, but on the inside you get the built-in].
>
> It seems to me that this is clearly a bug. The warning is useful, but
> a direct call to a function with a visible local definition should
> _always_ find that local definition, or what are scope rules for?

In Erlang, it seems that the main use of scope rules is to make
interesting exceptions from them.

/Richard


Richard Carlsson (richardc_at_csd.uu.se) (This space intentionally left blank.)
E-mail: Richard.Carlsson_at_csd.uu.se WWW: http://user.it.uu.se/~richardc/
"Having users is like optimization: the wise course is to delay it."
-- Paul Graham


Post generated using Mail2Forum (http://m2f.sourceforge.net)
kenneth at erix.ericsson.
Posted: Wed Oct 15, 2003 2:37 pm Reply with quote
Guest
Well I just have to comment on this.
I don't think there are that many new features in the syntax the past 4
years.

The single most important news is in my opinion the Bit-syntax.

Some of the other features referred to by Sean and others are not at all
part of the language yet (but some are distributed as experimental).

- The Java style module naming is still distributed as experimental it
is not supported and should not in my opinion be mentioned for
beginners. It might be a good idea to make it official but we have not
decided to do that yet.

- There is ONE syntactic sugar construct regarding records #rec{_ = xx}
added.

- The new suggested syntactic sugar for type guards "f(I/integer) <->
f(I) when integer(I) is not added to the language yet and we have not
decided that it will.

- There are some additions regarding guards and guard BIFs.

But where are the rest of the new features cluttering the language?
Do you think this is a lot of new things over a 4 year period?
Do you consider the functions in the kernel and stdlib to be part of the
language? Well I think that is a different discussion.

I think the record syntax and semantics is something to regret. It is an
important feature to have structured datatypes with names on them but
not the way records are implemented.

In summary I agree that we should be careful with language extensions
and I think that we really are.

/Kenneth (from the OTP team at Ericsson)

Kostis Sagonas wrote:
> On Mon, 13 Oct 2003, Sean Hinde wrote:
> >
> > I think there is and has been quite a bit of action since the bit
> > syntax. Duplicate guards, much new syntactic sugar for record
> > operations #rec{_ = xx}, Java style module naming, soon to be more
> > syntactic sugar for guards, Parameterised modules.. Some of these new
> > features have led to head scratching and questions to me from folks
> > here learning Erlang in the last few weeks. I think we *are* in severe
> > danger of making the core language "too big".
> >
> > We haven't "taken anything out of the language" to add any of these
> > things, and none of them add new capabilities to the language. All of
> > them must be understood by anyone learning Erlang, and already they
> > cannot all be taught in a week.
>
> Although I sympathise with Sean's concerns to some extent, I am having
> trouble sharing all his worries. Erlang is a small language and I fail
> to see why some of the "recently added features" are needed to be taught
> in a course that introduces the language to developers, or scare away
> people.
>
> Some examples to illustrate my point:
>
> 1. "Duplicate guards": There is absolutely no need to teach the old
> guards. Simply introduce the new is_* ones!
>
> [In fact, this is exaclty the point where the OTP team could have
> been more agressive in issuing *warnings* about using old guards,
> so that applications would be forced to upgrade sooner... but I
> guess they want to be spared the hassle from the (paying) user
> community. This way, things could even possibly be removed from
> the language, and there would not even be a need to mention
> the existence of the old ones.]
>
> 2. "Java style module naming"
> Is this so difficult a concept to grasp?
> If one thinks the answer is NO, then what's the problem?
> If the answer is YES, then is there really needed for this
> concept to be mentioned to somebody who wants to find out
> what Erlang is all about?
>
> 3. "Parameterized modules"
> This extension is not even available anywhere yet... it is
> already being taught in courses?
>
> Is there something I am missing?
>
> Cheers,
> Kostis
>
> PS. On Friday, I sent a mail about something I want added to the bit
> syntax, but it is still unanswered Wink
>


--
Kenneth Lundin Ericsson AB
kenneth_at_erix.ericsson.se
joachim.durchholz at web.
Posted: Thu Oct 16, 2003 5:29 pm Reply with quote
Guest
Eric Merritt wrote:
> Why is it impossible to take something away? If you
> give ample warning, say depricating a feature two or
> three releases before it goes away, and provide a very
> clear migration path to new features it should not be
> a problem to remove features.

You also need a way to convert existing code that uses deprecated
features. The conversion must not take more than O(1), O(log LOC) just
might be OK, O (LOC) would be out of the question.
And it's d*mned f*cking hard to offer such a migration part. It almost
invariably means some automatic conversion tools, and getting such
one-shot conversion tools written, tested and debugged is one of those
things that tend to sort-of work. (I have worked in a company where such
things were done, though I haven't worked directly with them - but I got
told the war stories, and the above is what the stories agreed on.)

Regards,
Jo



Post generated using Mail2Forum (http://m2f.sourceforge.net)

Display posts from previous:  

All times are GMT
Page 3 of 4
Goto page Previous  1, 2, 3, 4  Next
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum