Skip to content

If/else compiles however conditional operator does not #1904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
NiamhG opened this issue Oct 12, 2021 · 3 comments
Closed

If/else compiles however conditional operator does not #1904

NiamhG opened this issue Oct 12, 2021 · 3 comments
Labels
least-upper-bound Proposals about improvements of the LUB algorithm question Further information is requested

Comments

@NiamhG
Copy link

NiamhG commented Oct 12, 2021

Hopefully this is in the right spot.

Version: Dart SDK version: 2.14.3 (stable) (Wed Sep 29 13:10:26 2021 +0200) on "windows_x64"

I am using Android Studio 3.6.3.

The following function works:

Future<Result<Map<String, dynamic>>> withResult(Future<Response> Function() f) async {
  final response = await f();
  late final Map<String, dynamic> body;
  try {
    body = jsonDecode(response.body);
  } catch (e) {
    return ErrorResult("Unknown error.");
  }
  if (response.statusCode == 200) {
    return ValueResult(body);
  } else {
    return ErrorResult(body);
  }
}

However when changing the final if/else to a conditional operator, it does not, and throws the error:
"A value of type 'Object' can't be returned from the function 'withResult' because it has a return type of 'Future<Result<Map<String, dynamic>>>'.

Future<Result<Map<String, dynamic>>> withResult(Future<Response> Function() f) async {
  final response = await f();
  late final Map<String, dynamic> body;
  try {
    body = jsonDecode(response.body);
  } catch (e) {
    return ErrorResult("Unknown error.");
  }
  return response.statusCode == 200 ? ValueResult(body) : ErrorResult(body);
}

I would have thought these 2 operators to be functionally the same, should it be working like this? Thanks!

@srawlins
Copy link
Member

The static type of a conditional expression is the Least Upper Bound of the static type of the two cases. ValueResult<T> extends Result<T> but ErrorResult extends Result<Never>, so their LUB is Object.

The type of an expression returned should be assignable to the return type, but Object is not assignable to Result<Map<String, dynamic>>. You've hit on a limitation of LUB, perhaps #1877.

@eernstg eernstg transferred this issue from dart-lang/sdk Oct 13, 2021
@eernstg eernstg added least-upper-bound Proposals about improvements of the LUB algorithm question Further information is requested labels Oct 13, 2021
@eernstg
Copy link
Member

eernstg commented Oct 13, 2021

I moved this issue to the language repository and marked it with the label 'least-upper-bound', such that it is included in the group of issues on this topic area.

@eernstg
Copy link
Member

eernstg commented Apr 24, 2024

At this time the proposal in #1618 has been implemented (that is --enable-experiment=inference-update-3 is now enabled by default), and this eliminates the inconvenient typing of the conditional expression that used to give rise to a compile-time error. This means that the fix is in the pipeline and it will be available soon.

In particular, the following code is accepted by the analyzer and the common front end with no errors, with dart and dart analyze from c42fd69433ca0741fda5ecf82803aaa2fda24165:

// ----------------------------------------------------------------------
// Glue code, added by eernst.

import 'dart:convert';

class Result<X> {}

class ErrorResult extends Result<Never> {
  final Object message;
  ErrorResult(this.message);
}

class ValueResult<X> extends Result<X> {
  final X value;
  ValueResult(this.value);
}

class Response {
  String get body => '';
  int get statusCode => 42;
}

// ----------------------------------------------------------------------
// Code from the issue.

Future<Result<Map<String, dynamic>>> withResult1(
    Future<Response> Function() f) async {
  final response = await f();
  late final Map<String, dynamic> body;
  try {
    body = jsonDecode(response.body);
  } catch (e) {
    return ErrorResult("Unknown error.");
  }
  if (response.statusCode == 200) {
    return ValueResult(body);
  } else {
    return ErrorResult(body);
  }
}

Future<Result<Map<String, dynamic>>> withResult2(
    Future<Response> Function() f) async {
  final response = await f();
  late final Map<String, dynamic> body;
  try {
    body = jsonDecode(response.body);
  } catch (e) {
    return ErrorResult("Unknown error.");
  }
  return response.statusCode == 200 ? ValueResult(body) : ErrorResult(body);
}

void main() {}

@eernstg eernstg closed this as completed Apr 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
least-upper-bound Proposals about improvements of the LUB algorithm question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants