[go: up one dir, main page]

|
|
Log in / Subscribe / Register

Little things that matter in language design: make it do what it looks like it does

Little things that matter in language design: make it do what it looks like it does

Posted Jun 20, 2013 13:08 UTC (Thu) by Otus (subscriber, #67685)
In reply to: Little things that matter in language design: make it do what it looks like it does by NRArnot
Parent article: Little things that matter in language design

> I was surprised that Python didn't get a look in. By making the indentation define the statement grouping, it eliminates a class of error caused by code that "obviously" does something because of the (insignificant) whitespace that a human interprets as significant, and which actually parses as something different.

I used to think Python's significant whitespace was awful, but since using it more I find it actually rather pleasant to work with. However, I now find I hate the colon. Since the indent already tells you where a block starts, why is it needed? Google tells me it's because "explicit is better than implicit", but in that case why is the *end* of a block implicit? Makes no sense to me...


to post comments

Little things that matter in language design: make it do what it looks like it does

Posted Jun 20, 2013 21:32 UTC (Thu) by neilbrown (subscriber, #359) [Link] (8 responses)

I actually like the colon. It clearly marks the end of the condition and the start of the statement block.

I don't think a newline-followed-by-indent clearly marks an end so well. I can write:

  if something and (otherthing
                    or  whatever) :
       statements
and the first "newline-followed-by-indent" doesn't mark the end of anything.

So the requirement of a colon causes unbalanced brackets in the condition to be easily detected. Without it the compiler might not notice until much later.

A "dedent" (I think that is what python call the opposite of indent), on the other hand, always clearly marks the end of something. There is no uncertainty so no need for extra syntax.

Little things that matter in language design: make it do what it looks like it does

Posted Dec 28, 2014 8:29 UTC (Sun) by maryjmcdermott57 (guest, #100380) [Link] (7 responses)

A little bit back to your article.
I want to ask one question about Rust.

First of all, I want to say thank you for your article. You have the answer for my question (the section "semicolons & expression"), that I asked when should add ; at the end of whole if/else expression because it's also an expression. I asked that question in many forums but many people either not pay attention to it or thinking that it's as a silly question.

But as you answered my question. This leads to more questions.
As you said, I assume that in Rust, if the expression return the unit-() type then we wouldn't require add ; at the end of that expression.

As before, if the internal of if/else expression (i.e function call return unit-() type then we won't necessary add ; at the end of either each internal function call or the whole if/else expression.

So what about the function call outside of if/else expression.
The rule seems not true anymore
I mean I have this code

fn main() {
println!("hello") // I think don't need add ; at here but it's wrong
println!("world") // I think don't need add ; at here but it's wrong
}

As the code run, compile raise error. Why does that happens when println!() return unit-() type? So as the assumption above, this code should work.

And can I ask you one more question? Is the function declaration is expression or not? Because I don't see the ; at the end of } of function declaration. I mean if it's an expression, it should look like this

fn foo() {
// do something
}; // ; should add in here but in practical, it's not there

Little things that matter in language design: make it do what it looks like it does

Posted Dec 28, 2014 9:15 UTC (Sun) by Cyberax (✭ supporter ✭, #52523) [Link] (1 responses)

This works just fine:
>
>fn main()
>{
> println!("Hello, world!")
>}
>

Here you have a 'fn main()' returning the result of 'println!' invocation (a macro).

Little things that matter in language design: make it do what it looks like it does

Posted Dec 28, 2014 13:16 UTC (Sun) by maryjmcdermott57 (guest, #100380) [Link]

Yes. I already know that if there is just 1 function call like your example, I can omit the ; at the end of println!()

But what I want to know is that why although both println!("hello") & println!("world") return unit-() type, we still need separate each of these with ;

Because as you saw in the article, if the return value inside if/else is unit-() type, it don't need to add ; at the end of whole if/else expression. Otherwise we have to.

Little things that matter in language design: make it do what it looks like it does

Posted Dec 29, 2014 9:11 UTC (Mon) by jem (subscriber, #24231) [Link] (4 responses)

"As you said, I assume that in Rust, if the expression return the unit-() type then we wouldn't require add ; at the end of that expression."

No, it's the other way around: if you add a semicolon at the end of an expression it turns the expression into a statement. Doing this throws away the value of the expression and returns () instead.

Rust does not allow an expression to follow another expression, you will have to turn all but the last consecutive expression into statements by inserting semicolons after them. This means that you are only interested in the side effects of all but the last expressions, and return the value of the last expression. If you wish, you can put a semicolon after the last expression too, if the value of the last expression is not useful.

Little things that matter in language design: make it do what it looks like it does

Posted Dec 29, 2014 10:26 UTC (Mon) by maryjmcdermott57 (guest, #100380) [Link] (3 responses)

With your answer, I summed up like this
- with the last expression in a block, add ; is up to me (depend on my intention)

But it's also give me more confusing. So can you explain a little bit more about this code.

if condition {
function1()
} else {
function2()
}
expression3;

With this code above, the if/else is not last expression. And if both function don't return value so we don't need add ; at the end of } of whole if/else. That makes sense (as author said that the language doesn't require that ; if whole if/else doesn't have value). With that knowledge, why we have to add ; at the end of println!("hello"). Because println!("hello") also doesn't return any value

fn main() {
println!("hello") // why we have to add ; at here
println!("world")
}

And if can, please answer me one more question. What about other blocks like match, loop, struct, function declaration? These are also expression as whole or not.

Because I saw function declarations next each other without ; between them. like this

fn foo() {
// ...
} // don't have ; at here
fn bar() {
// ...
}

If they are expression, we have separate them with ; to compile correct, right?

Please bear with me if my questions make you annoying. I'm very confusing about these and I also add question in other places but not get the good answer or some just ignore & vote close topic.

Little things that matter in language design: make it do what it looks like it does

Posted Dec 29, 2014 10:51 UTC (Mon) by Cyberax (✭ supporter ✭, #52523) [Link] (1 responses)

>fn main() {
>println!("hello") // why we have to add ; at here
>println!("world")
>}

You need ';' because you can't just combine two expressions together. What operation should be used for that?

(never mind the fact that units can't be used in _any_ operation)

Little things that matter in language design: make it do what it looks like it does

Posted Dec 29, 2014 11:21 UTC (Mon) by maryjmcdermott57 (guest, #100380) [Link]

Yes, of course I can't combine 2 expressions together. So what about if/else & expression3. Both are expressions, right? But we can omit the ; at if/else expression in some cases. That makes no sense if we can omit ; at if/else expression but can't do that with println!("hello"). If we want consistent, Rust should force add ; at if/else (after the closing } of else) expression too

Little things that matter in language design: make it do what it looks like it does

Posted Dec 29, 2014 12:50 UTC (Mon) by jem (subscriber, #24231) [Link]

"With this code above, the if/else is not last expression. And if both function don't return value so we don't need add ; at the end of } of whole if/else. That makes sense (as author said that the language doesn't require that ; if whole if/else doesn't have value)."

You don't put a semicolon at the end of } of the whole if/else. This has nothing to do with whether the if should return a value or not – you never put a semicolon there. The if/else returns a value if the last expressions in the if and else branches do not end with a semicolon.

"What about other blocks like match, loop, struct, function declaration? These are also expression as whole or not."

Just like in the if/else case, you don't put a semicolon there. As with the if case, this does not mean these constructs have a value. Rust (mostly) borrows this syntax from C.

I think the best way of thinking about this is not to try to minimize the amount of semicolons. Do not focus all the time on whether you can leave out a semicolon, but instead think "do I want to return the value of the last expression in this block as the value of the block?". If that is the case, then you should leave out the semicolon.

Little things that matter in language design: make it do what it looks like it does

Posted Jun 21, 2013 8:41 UTC (Fri) by renox (guest, #23785) [Link]

> "explicit is better than implicit"

Bah, this is very selectively applied in Python, for example other languages distinguish variable declaration from variable assignment:
var x = ... (declare x and assign a value to it)
x = ... (only assignment)
in Python you only have "x = ...": the first assignment implicitly declare x.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds