shiika icon indicating copy to clipboard operation
shiika copied to clipboard

Allow `?` for method suffix?

Open yhara opened this issue 4 years ago • 6 comments

I've not decided whether to allow ? as method suffix (like Ruby) or not.

If allowed, the method must return Bool.

yhara avatar Jan 14 '21 14:01 yhara

The reason not to introduce this is Rust's ? operator.

If Shiika won't have exceptions and stick to Result<T, E>, there should be something like ? in Rust.

My concern is that they may conflicts in syntax or make the code cryptic... but considering foo? does not return Result (because it returns Bool), maybe it's ok?

yhara avatar Jan 14 '21 14:01 yhara

Just some code that shows that it might actually be confusing:

class A
	def full? -> bool
		true
	end

	def empty -> Result<Int>
		# Not sure if this is the syntax...
		Result.ok(5)
	end
end

class B
	def use_a -> Result<Int>
		a = A.new		
		
		# ...
		# Imagine this being a larger function body, not only like 5 lines
		
		b = a.full? # Holds bool
		c = a.empty? # Holds 
		
		# More code
		Result.ok(1)	
	end
end

Depending on how "far away" the code that uses both these syntax is, it might be hard to understand properly. If one already forgot the context (a method returning Result) they might assume that both return a boolean.

mainrs avatar Mar 20 '21 18:03 mainrs

Good point. Having two different ? (no, three, because there is ? :) seems too confusing. So the options are:

  1. Add method name suffix ? only (= Ruby)
  2. Add ? for Result only
  3. Add method name suffix ? + another facility for Result
    • Rust had try! macro before ? is introduced.
    • Scala's for expression can be used to simplify computation with Either, Future, etc.
    • Go2 may have something for this problem
    • etc.

yhara avatar Apr 06 '21 14:04 yhara

It depends on whether you want to stick more to Ruby or Rust. If it's Ruby, I'd say the method suffix is probably the right choice. If it's Rust, the ? operator should stick.

Go2 looks definitely better than Go(1) and the pure boilerplate of error handling was why I left the language untouched after I tried it out a couple of times. Although for me, it is still too verbose. I think Rust does it better while still being able to keep the same "power level" due to mapping of error types.

Swift has the guard keyword: https://stackoverflow.com/questions/30791488/swifts-guard-keyword Maybe something like this? Feels neither Rust-y nor Ruby-y (:smile:) but might work:

class A
  def returns_error -> Result<Int, ()>
    Result.ok(5)
  end

  def early_return_if_error -> Result<Int, ()>
    guard v = returns_error # or v = guard returns_error || v = check returns_error
    Result.ok(v * 2)
  end
end

mainrs avatar Apr 06 '21 14:04 mainrs

I would like to suggest expr.try (pick any keyword for try), which works same as expr? and is parsed same as expr.await.

Having both ident? and expr? is technically okay. To do so, compiler implementation needs some effort. A possible way is that lexer reads ident? as ident+operator and compiler combines them later if ident doesn't exist. (I don't think the effort and language complexity are worthwhile for ? operator.)

vain0x avatar Apr 06 '21 16:04 vain0x

res = returns_error.try. Looks good to me!

mainrs avatar Apr 06 '21 17:04 mainrs