├── .gitattributes ├── .github ├── CODEOWNERS └── ISSUE_TEMPLATE │ ├── config.yml │ ├── docs-feedback.yml │ └── proposal_template.md ├── .gitignore ├── CODE-OF-CONDUCT.md ├── Communities.md ├── Design-Process.md ├── Language-Version-History.md ├── README.md ├── meetings ├── 2013 │ ├── LDM-2013-10-07.md │ ├── LDM-2013-10-21.md │ ├── LDM-2013-11-04.md │ ├── LDM-2013-12-16.md │ └── README.md ├── 2014 │ ├── LDM-2014-01-06.md │ ├── LDM-2014-02-03.md │ ├── LDM-2014-02-10.md │ ├── LDM-2014-04-21.md │ ├── LDM-2014-05-07.md │ ├── LDM-2014-05-21.md │ ├── LDM-2014-07-09.md │ ├── LDM-2014-08-27.md │ ├── LDM-2014-09-03.md │ ├── LDM-2014-10-01.md │ ├── LDM-2014-10-15.md │ └── README.md ├── 2015 │ ├── LDM-2015-01-21.md │ ├── LDM-2015-01-28.md │ ├── LDM-2015-02-04.md │ ├── LDM-2015-02-11.md │ ├── LDM-2015-03-04.md │ ├── LDM-2015-03-10-17.md │ ├── LDM-2015-03-18.md │ ├── LDM-2015-03-24.md │ ├── LDM-2015-03-25-Design-Review.md │ ├── LDM-2015-03-25-Notes.md │ ├── LDM-2015-04-01-08.md │ ├── LDM-2015-04-14.md │ ├── LDM-2015-04-15.md │ ├── LDM-2015-04-22-Design-Review.md │ ├── LDM-2015-05-20.md │ ├── LDM-2015-05-25.md │ ├── LDM-2015-07-01.md │ ├── LDM-2015-07-07.md │ ├── LDM-2015-08-18.md │ ├── LDM-2015-09-01.md │ ├── LDM-2015-09-02.md │ ├── LDM-2015-09-08.md │ ├── LDM-2015-10-07-Design-Review.md │ ├── LDM-2015-11-02-Design-Demo.md │ └── README.md ├── 2016 │ ├── LDM-2016-02-29.md │ ├── LDM-2016-04-06.md │ ├── LDM-2016-04-12-22.md │ ├── LDM-2016-05-03-04.md │ ├── LDM-2016-05-10.md │ ├── LDM-2016-07-12.md │ ├── LDM-2016-07-13.md │ ├── LDM-2016-07-15.md │ ├── LDM-2016-08-24.md │ ├── LDM-2016-09-06.md │ ├── LDM-2016-10-18.md │ ├── LDM-2016-10-25-26.md │ ├── LDM-2016-11-01.md │ ├── LDM-2016-11-15.md │ ├── LDM-2016-11-16.md │ ├── LDM-2016-11-30.md │ ├── LDM-2016-12-07-14.md │ └── README.md ├── 2017 │ ├── CLR-2017-03-23.md │ ├── LDM-2017-01-10.md │ ├── LDM-2017-01-11.md │ ├── LDM-2017-01-17.md │ ├── LDM-2017-01-18.md │ ├── LDM-2017-02-14.md │ ├── LDM-2017-02-15.md │ ├── LDM-2017-02-21.md │ ├── LDM-2017-02-22.md │ ├── LDM-2017-02-28.md │ ├── LDM-2017-03-01.md │ ├── LDM-2017-03-07.md │ ├── LDM-2017-03-08.md │ ├── LDM-2017-03-15.md │ ├── LDM-2017-03-21.md │ ├── LDM-2017-03-28.md │ ├── LDM-2017-03-29.md │ ├── LDM-2017-04-05.md │ ├── LDM-2017-04-11.md │ ├── LDM-2017-04-18.md │ ├── LDM-2017-04-19.md │ ├── LDM-2017-05-16.md │ ├── LDM-2017-05-17.md │ ├── LDM-2017-05-26.md │ ├── LDM-2017-05-31.md │ ├── LDM-2017-06-13.md │ ├── LDM-2017-06-14.md │ ├── LDM-2017-06-27.md │ ├── LDM-2017-06-28.md │ ├── LDM-2017-07-05.md │ ├── LDM-2017-07-26.md │ ├── LDM-2017-08-07.md │ ├── LDM-2017-08-09.md │ ├── LDM-2017-08-14.md │ ├── LDM-2017-08-16.md │ ├── LDM-2017-08-21.md │ ├── LDM-2017-08-23.md │ ├── LDM-2017-08-28.md │ ├── LDM-2017-08-30.md │ ├── LDM-2017-09-25.md │ ├── LDM-2017-09-27.md │ ├── LDM-2017-10-02.md │ ├── LDM-2017-10-04.md │ ├── LDM-2017-10-09.md │ ├── LDM-2017-10-11.md │ ├── LDM-2017-10-16.md │ ├── LDM-2017-10-18.md │ ├── LDM-2017-10-25.md │ ├── LDM-2017-11-06.md │ ├── LDM-2017-11-08.md │ ├── LDM-2017-11-20.md │ ├── LDM-2017-11-27.md │ ├── LDM-2017-11-29.md │ ├── LDM-2017-12-04.md │ ├── LDM-2017-12-06.md │ └── README.md ├── 2018 │ ├── LDM-2018-01-03.md │ ├── LDM-2018-01-10.md │ ├── LDM-2018-01-18.md │ ├── LDM-2018-01-22.md │ ├── LDM-2018-01-24.md │ ├── LDM-2018-01-31.md │ ├── LDM-2018-02-05.md │ ├── LDM-2018-02-07.md │ ├── LDM-2018-02-14.md │ ├── LDM-2018-02-21.md │ ├── LDM-2018-02-26.md │ ├── LDM-2018-02-28.md │ ├── LDM-2018-03-14.md │ ├── LDM-2018-03-19.md │ ├── LDM-2018-03-21.md │ ├── LDM-2018-03-28.md │ ├── LDM-2018-04-02.md │ ├── LDM-2018-04-04.md │ ├── LDM-2018-04-25.md │ ├── LDM-2018-04-30.md │ ├── LDM-2018-05-02.md │ ├── LDM-2018-05-14.md │ ├── LDM-2018-05-21.md │ ├── LDM-2018-05-23.md │ ├── LDM-2018-05-30.md │ ├── LDM-2018-06-04.md │ ├── LDM-2018-06-06.md │ ├── LDM-2018-06-25.md │ ├── LDM-2018-07-09.md │ ├── LDM-2018-07-11.md │ ├── LDM-2018-07-16.md │ ├── LDM-2018-08-20.md │ ├── LDM-2018-08-22.md │ ├── LDM-2018-09-05.md │ ├── LDM-2018-09-10.md │ ├── LDM-2018-09-19.md │ ├── LDM-2018-09-24.md │ ├── LDM-2018-09-26.md │ ├── LDM-2018-10-01.md │ ├── LDM-2018-10-03.md │ ├── LDM-2018-10-10.md │ ├── LDM-2018-10-15.md │ ├── LDM-2018-10-17.md │ ├── LDM-2018-10-22.md │ ├── LDM-2018-10-24.md │ ├── LDM-2018-10-29.md │ ├── LDM-2018-10-31.md │ ├── LDM-2018-11-05.md │ ├── LDM-2018-11-14.md │ ├── LDM-2018-11-28.md │ ├── LDM-2018-12-03.md │ ├── LDM-2018-12-05.md │ ├── LDM-2018-12-12.md │ └── README.md ├── 2019 │ ├── LDM-2019-01-07.md │ ├── LDM-2019-01-09.md │ ├── LDM-2019-01-14.md │ ├── LDM-2019-01-16.md │ ├── LDM-2019-01-23.md │ ├── LDM-2019-02-13.md │ ├── LDM-2019-02-20.md │ ├── LDM-2019-02-25.md │ ├── LDM-2019-02-27.md │ ├── LDM-2019-03-04.md │ ├── LDM-2019-03-06.md │ ├── LDM-2019-03-13.md │ ├── LDM-2019-03-19.md │ ├── LDM-2019-03-25.md │ ├── LDM-2019-03-27.md │ ├── LDM-2019-04-01.md │ ├── LDM-2019-04-03.md │ ├── LDM-2019-04-15.md │ ├── LDM-2019-04-22.md │ ├── LDM-2019-04-24.md │ ├── LDM-2019-04-29.md │ ├── LDM-2019-05-13.md │ ├── LDM-2019-05-15.md │ ├── LDM-2019-07-10.md │ ├── LDM-2019-07-17.md │ ├── LDM-2019-07-22.md │ ├── LDM-2019-08-26.md │ ├── LDM-2019-08-28.md │ ├── LDM-2019-09-04.md │ ├── LDM-2019-09-11.md │ ├── LDM-2019-09-16.md │ ├── LDM-2019-09-18.md │ ├── LDM-2019-10-21.md │ ├── LDM-2019-10-23.md │ ├── LDM-2019-10-28.md │ ├── LDM-2019-10-30.md │ ├── LDM-2019-11-11.md │ ├── LDM-2019-11-13.md │ ├── LDM-2019-11-18.md │ ├── LDM-2019-11-25.md │ ├── LDM-2019-12-11.md │ ├── LDM-2019-12-16.md │ ├── LDM-2019-12-18.md │ └── README.md ├── 2020 │ ├── LDM-2020-01-06.md │ ├── LDM-2020-01-08.md │ ├── LDM-2020-01-15.md │ ├── LDM-2020-01-22.md │ ├── LDM-2020-01-29.md │ ├── LDM-2020-02-03.md │ ├── LDM-2020-02-05.md │ ├── LDM-2020-02-10.md │ ├── LDM-2020-02-12.md │ ├── LDM-2020-02-19.md │ ├── LDM-2020-02-24.md │ ├── LDM-2020-02-26.md │ ├── LDM-2020-03-09.md │ ├── LDM-2020-03-23.md │ ├── LDM-2020-03-25.md │ ├── LDM-2020-03-30.md │ ├── LDM-2020-04-01.md │ ├── LDM-2020-04-06.md │ ├── LDM-2020-04-08.md │ ├── LDM-2020-04-13.md │ ├── LDM-2020-04-15.md │ ├── LDM-2020-04-20.md │ ├── LDM-2020-04-27.md │ ├── LDM-2020-05-04.md │ ├── LDM-2020-05-06.md │ ├── LDM-2020-05-11.md │ ├── LDM-2020-05-27.md │ ├── LDM-2020-06-01.md │ ├── LDM-2020-06-10.md │ ├── LDM-2020-06-15.md │ ├── LDM-2020-06-17.md │ ├── LDM-2020-06-22.md │ ├── LDM-2020-06-24.md │ ├── LDM-2020-06-29.md │ ├── LDM-2020-07-01.md │ ├── LDM-2020-07-06.md │ ├── LDM-2020-07-13.md │ ├── LDM-2020-07-20.md │ ├── LDM-2020-07-27.md │ ├── LDM-2020-08-24.md │ ├── LDM-2020-09-09.md │ ├── LDM-2020-09-14.md │ ├── LDM-2020-09-16.md │ ├── LDM-2020-09-23.md │ ├── LDM-2020-09-28.md │ ├── LDM-2020-09-30.md │ ├── LDM-2020-10-05.md │ ├── LDM-2020-10-07.md │ ├── LDM-2020-10-12.md │ ├── LDM-2020-10-14.md │ ├── LDM-2020-10-21.md │ ├── LDM-2020-10-26.md │ ├── LDM-2020-11-04.md │ ├── LDM-2020-11-11.md │ ├── LDM-2020-11-16.md │ ├── LDM-2020-12-02.md │ ├── LDM-2020-12-07.md │ ├── LDM-2020-12-14.md │ ├── LDM-2020-12-16.md │ ├── README.md │ ├── Required_Properties_2020_09_16.pdf │ └── delectable_tea_2020_07_27.png ├── 2021 │ ├── LDM-2021-01-05.md │ ├── LDM-2021-01-11.md │ ├── LDM-2021-01-13.md │ ├── LDM-2021-01-27.md │ ├── LDM-2021-02-03.md │ ├── LDM-2021-02-08.md │ ├── LDM-2021-02-10.md │ ├── LDM-2021-02-22.md │ ├── LDM-2021-02-24.md │ ├── LDM-2021-03-01.md │ ├── LDM-2021-03-03.md │ ├── LDM-2021-03-10.md │ ├── LDM-2021-03-15.md │ ├── LDM-2021-03-24.md │ ├── LDM-2021-03-29.md │ ├── LDM-2021-04-05.md │ ├── LDM-2021-04-07.md │ ├── LDM-2021-04-12.md │ ├── LDM-2021-04-14.md │ ├── LDM-2021-04-19.md │ ├── LDM-2021-04-21.md │ ├── LDM-2021-04-28.md │ ├── LDM-2021-05-03.md │ ├── LDM-2021-05-10.md │ ├── LDM-2021-05-12.md │ ├── LDM-2021-05-17.md │ ├── LDM-2021-05-19.md │ ├── LDM-2021-05-26.md │ ├── LDM-2021-06-02.md │ ├── LDM-2021-06-07.md │ ├── LDM-2021-06-14.md │ ├── LDM-2021-06-21.md │ ├── LDM-2021-07-12.md │ ├── LDM-2021-07-19.md │ ├── LDM-2021-07-26.md │ ├── LDM-2021-08-23.md │ ├── LDM-2021-08-25.md │ ├── LDM-2021-08-30.md │ ├── LDM-2021-09-01.md │ ├── LDM-2021-09-13.md │ ├── LDM-2021-09-15.md │ ├── LDM-2021-09-20.md │ ├── LDM-2021-09-22.md │ ├── LDM-2021-10-13.md │ ├── LDM-2021-10-20.md │ ├── LDM-2021-10-25.md │ ├── LDM-2021-10-27.md │ ├── LDM-2021-11-01.md │ ├── LDM-2021-11-03.md │ ├── LDM-2021-11-10.md │ ├── LDM-2021-12-01.md │ ├── LDM-2021-12-15.md │ └── README.md ├── 2022 │ ├── LDM-2022-01-03.md │ ├── LDM-2022-01-05-OHIMark.jpg │ ├── LDM-2022-01-05.md │ ├── LDM-2022-01-12.md │ ├── LDM-2022-01-24.md │ ├── LDM-2022-01-26.md │ ├── LDM-2022-02-07.md │ ├── LDM-2022-02-09.md │ ├── LDM-2022-02-14.md │ ├── LDM-2022-02-16.md │ ├── LDM-2022-02-23.md │ ├── LDM-2022-02-28.md │ ├── LDM-2022-03-02.md │ ├── LDM-2022-03-09.md │ ├── LDM-2022-03-14.md │ ├── LDM-2022-03-21.md │ ├── LDM-2022-03-23.md │ ├── LDM-2022-03-28.md │ ├── LDM-2022-03-30.md │ ├── LDM-2022-04-06.md │ ├── LDM-2022-04-11.md │ ├── LDM-2022-04-13.md │ ├── LDM-2022-04-18.md │ ├── LDM-2022-04-25.md │ ├── LDM-2022-04-27.md │ ├── LDM-2022-05-02.md │ ├── LDM-2022-05-09.md │ ├── LDM-2022-05-11.md │ ├── LDM-2022-05-23.md │ ├── LDM-2022-06-06.md │ ├── LDM-2022-06-29.md │ ├── LDM-2022-07-13.md │ ├── LDM-2022-07-27.md │ ├── LDM-2022-08-03.md │ ├── LDM-2022-08-10.md │ ├── LDM-2022-08-24.md │ ├── LDM-2022-08-31.md │ ├── LDM-2022-09-21.md │ ├── LDM-2022-09-26.md │ ├── LDM-2022-09-28.md │ ├── LDM-2022-10-05.md │ ├── LDM-2022-10-10.md │ ├── LDM-2022-10-12.md │ ├── LDM-2022-10-17.md │ ├── LDM-2022-10-19.md │ ├── LDM-2022-10-26.md │ ├── LDM-2022-11-02.md │ ├── LDM-2022-11-30.md │ ├── LDM-2022-12-14.md │ └── README.md ├── 2023 │ ├── LDM-2023-01-09.md │ ├── LDM-2023-01-11.md │ ├── LDM-2023-01-18.md │ ├── LDM-2023-02-01.md │ ├── LDM-2023-02-15.md │ ├── LDM-2023-02-22.md │ ├── LDM-2023-02-27.md │ ├── LDM-2023-03-01.md │ ├── LDM-2023-03-08.md │ ├── LDM-2023-03-13.md │ ├── LDM-2023-04-03.md │ ├── LDM-2023-04-10.md │ ├── LDM-2023-04-26.md │ ├── LDM-2023-05-01.md │ ├── LDM-2023-05-03.md │ ├── LDM-2023-05-08.md │ ├── LDM-2023-05-15.md │ ├── LDM-2023-05-17.md │ ├── LDM-2023-05-31.md │ ├── LDM-2023-06-05.md │ ├── LDM-2023-06-19.md │ ├── LDM-2023-07-12.md │ ├── LDM-2023-07-17.md │ ├── LDM-2023-07-24.md │ ├── LDM-2023-07-26.md │ ├── LDM-2023-07-31.md │ ├── LDM-2023-08-07.md │ ├── LDM-2023-08-09.md │ ├── LDM-2023-08-14.md │ ├── LDM-2023-08-16.md │ ├── LDM-2023-09-18.md │ ├── LDM-2023-09-20.md │ ├── LDM-2023-09-25.md │ ├── LDM-2023-09-27.md │ ├── LDM-2023-10-02.md │ ├── LDM-2023-10-04 Intro to Trimming and AOT.pdf │ ├── LDM-2023-10-04.md │ ├── LDM-2023-10-09.md │ ├── LDM-2023-10-11-specification-update.md │ ├── LDM-2023-10-11.md │ ├── LDM-2023-10-16.md │ ├── LDM-2023-11-15.md │ ├── LDM-2023-11-27.md │ ├── LDM-2023-12-04.md │ ├── LDM-2023-12-11.md │ └── README.md ├── 2024 │ ├── LDM-2024-01-08.md │ ├── LDM-2024-01-10.md │ ├── LDM-2024-01-22.md │ ├── LDM-2024-01-29.md │ ├── LDM-2024-01-31.md │ ├── LDM-2024-02-05.md │ ├── LDM-2024-02-07.md │ ├── LDM-2024-02-21.md │ ├── LDM-2024-02-26.md │ ├── LDM-2024-02-28.md │ ├── LDM-2024-03-04.md │ ├── LDM-2024-03-11.md │ ├── LDM-2024-03-27-presentation.pdf │ ├── LDM-2024-03-27.md │ ├── LDM-2024-04-01-presentation.pdf │ ├── LDM-2024-04-01.md │ ├── LDM-2024-04-08.md │ ├── LDM-2024-04-15.md │ ├── LDM-2024-04-17.md │ ├── LDM-2024-04-22.md │ ├── LDM-2024-04-24.md │ ├── LDM-2024-05-01.md │ ├── LDM-2024-05-08.md │ ├── LDM-2024-05-13.md │ ├── LDM-2024-05-15-KeyValuePairCorrespondence.md │ ├── LDM-2024-05-15.md │ ├── LDM-2024-06-03.md │ ├── LDM-2024-06-10.md │ ├── LDM-2024-06-12.md │ ├── LDM-2024-06-17.md │ ├── LDM-2024-06-24.md │ ├── LDM-2024-06-26.md │ ├── LDM-2024-07-15-usage-data.md │ ├── LDM-2024-07-15.md │ ├── LDM-2024-07-17.md │ ├── LDM-2024-07-22-ref-struct-interface-examples.md │ ├── LDM-2024-07-22.md │ ├── LDM-2024-07-24.md │ ├── LDM-2024-08-14.md │ ├── LDM-2024-08-19.md │ ├── LDM-2024-08-21.md │ ├── LDM-2024-08-26.md │ ├── LDM-2024-08-28.md │ ├── LDM-2024-09-04.md │ ├── LDM-2024-09-11.md │ ├── LDM-2024-09-18.md │ ├── LDM-2024-09-30.md │ ├── LDM-2024-10-02.md │ ├── LDM-2024-10-07-extension-compat.md │ ├── LDM-2024-10-07.md │ ├── LDM-2024-10-09.md │ ├── LDM-2024-10-14-Enumerable-extension.cs │ ├── LDM-2024-10-14-Enumerable-extensions.cs │ ├── LDM-2024-10-14.md │ ├── LDM-2024-10-16.md │ ├── LDM-2024-10-28.md │ ├── LDM-2024-10-30.md │ ├── LDM-2024-11-04-patterns.md │ ├── LDM-2024-11-04.md │ ├── LDM-2024-11-13.md │ ├── LDM-2024-11-20.md │ ├── LDM-2024-12-04.md │ ├── LDM-2024-12-09.md │ └── README.md ├── 2025 │ ├── LDM-2025-01-06.md │ ├── LDM-2025-01-13.md │ ├── LDM-2025-01-15.md │ ├── LDM-2025-01-22.md │ ├── LDM-2025-02-12.md │ ├── LDM-2025-02-19.md │ ├── LDM-2025-02-24.md │ ├── LDM-2025-02-26.md │ ├── LDM-2025-03-03.md │ ├── LDM-2025-03-05.md │ ├── LDM-2025-03-10.md │ ├── LDM-2025-03-12.md │ ├── LDM-2025-03-17.md │ ├── LDM-2025-03-19.md │ ├── LDM-2025-03-24.md │ ├── LDM-2025-04-02.md │ ├── LDM-2025-04-07.md │ ├── LDM-2025-04-09.md │ ├── LDM-2025-04-14.md │ ├── LDM-2025-04-16.md │ ├── LDM-2025-04-23.md │ ├── LDM-2025-05-05.md │ ├── LDM-2025-05-07.md │ ├── LDM-2025-05-12.md │ └── README.md ├── README.md └── working-groups │ ├── collection-literals │ ├── CL-2022-10-06.md │ ├── CL-2022-10-14.md │ ├── CL-2022-10-21.md │ ├── CL-2023-04-05.md │ ├── CL-2023-04-28.md │ ├── CL-2023-05-10.md │ ├── CL-2023-05-26.md │ ├── CL-2023-06-12.md │ ├── CL-2023-06-26.md │ ├── CL-2023-07-26.md │ ├── CL-2023-08-03.md │ ├── CL-2023-08-10.md │ ├── CL-2023-08-11.md │ ├── CL-2024-01-23.md │ ├── CL-LDM-2023-05-31.md │ ├── CL-LDM-2023-08-14.md │ ├── Compiler-synthesized-types.md │ ├── Core-interface-target-type-proposal.md │ ├── LDM-questions-2023-08-15.md │ ├── collection-expressions-inferred-type.md │ └── collection-expressions-next.md │ ├── discriminated-unions │ ├── DU-2022-10-19.md │ ├── DU-2022-10-24.md │ ├── DU-2022-10-31.md │ ├── DU-2022-11-07.md │ └── Union implementation challenges.md │ ├── expressions-statements │ └── ES-2022-11-30.md │ ├── extensions │ ├── Compatibility through coexistence between extension types and extension methods.md │ ├── Extension-API-docs.md │ ├── anonymous-extension-declarations.md │ ├── compat-mode-in-extensions.md │ ├── compromise-design-for-extensions.md │ ├── disambiguation-syntax-examples.md │ ├── extending-extensions-a-guide-to-relaxation.md │ ├── extension-member-disambiguation.md │ ├── extension-members-unified-proposal.md │ ├── extensions-an-evolution-of-extension-methods.md │ ├── extensions-as-static-types.md │ ├── extensions-lookup.md │ ├── extensions_v2.md │ ├── implicit-compatibility-for-ported-extension-methods.md │ ├── rename-to-roles-and-extensions.md │ └── the-design-space-for-extensions.md │ ├── field-keyword │ ├── FK-2024-06-26.md │ ├── FK-2024-08-07 Nullability analysis with the `field` keyword.md │ └── FK-2024-08-07.md │ ├── interceptors │ ├── IC-2023-03-20.md │ ├── IC-2023-04-04.md │ └── interceptors-issues-2024-01.md │ ├── nullability-improvements │ ├── NI-2022-10-24.md │ ├── NI-2022-11-01.md │ ├── NI-2022-11-07.md │ └── NI-2022-11-22.md │ ├── params-improvements │ ├── PI-2022-10-25.md │ └── PI-2022-11-03.md │ ├── ref-improvements │ ├── REF-2022-11-11.md │ └── ignore-overloads-in-expressions.md │ └── roles │ ├── extension-wg-2024-06-07.md │ ├── extension-wg-2024-06-14.md │ ├── extension-wg-2024-06-21.md │ ├── extensions-2023-02-21.md │ ├── extensions-wg-2023-04-27.md │ ├── extensions-wg-2023-06-07.md │ ├── extensions-wg-2024-03-05.md │ ├── extensions-wg-2024-08-09.md │ ├── roles-2022-11-10.md │ ├── roles-2023-01-23.md │ ├── roles-2023-01-25.md │ └── roles-2023-02-15.md ├── proposals ├── README.md ├── TypeUnions.md ├── block-bodied-switch-expression-arms.md ├── breaking-change-warnings.md ├── collection-expression-arguments.md ├── csharp-10.0 │ ├── GlobalUsingDirective.md │ ├── async-method-builders.md │ ├── caller-argument-expression.md │ ├── constant_interpolated_strings.md │ ├── enhanced-line-directives.md │ ├── extended-property-patterns.md │ ├── file-scoped-namespaces.md │ ├── improved-definite-assignment.md │ ├── improved-interpolated-strings.md │ ├── lambda-improvements.md │ ├── parameterless-struct-constructors.md │ └── record-structs.md ├── csharp-11.0 │ ├── auto-default-structs.md │ ├── checked-user-defined-operators.md │ ├── extended-nameof-scope.md │ ├── file-local-types.md │ ├── generic-attributes.md │ ├── list-patterns.md │ ├── low-level-struct-improvements.md │ ├── new-line-in-interpolation.md │ ├── numeric-intptr.md │ ├── pattern-match-span-of-char-on-string.md │ ├── raw-string-literal.md │ ├── relaxing_shift_operator_requirements.md │ ├── required-members.md │ ├── static-abstracts-in-interfaces.md │ ├── unsigned-right-shift-operator.md │ └── utf8-string-literals.md ├── csharp-12.0 │ ├── collection-expressions.md │ ├── experimental-attribute.md │ ├── inline-arrays.md │ ├── lambda-method-group-defaults.md │ ├── primary-constructors.md │ ├── ref-readonly-parameters.md │ └── using-alias-types.md ├── csharp-13.0 │ ├── collection-expressions-better-conversion.md │ ├── esc-escape-sequence.md │ ├── lock-object.md │ ├── method-group-natural-type-improvements.md │ ├── overload-resolution-priority.md │ ├── params-collections.md │ ├── partial-properties.md │ ├── ref-struct-interfaces.md │ └── ref-unsafe-in-iterators-async.md ├── csharp-6.0 │ ├── empty-params-array.md │ ├── enum-base-type.md │ └── struct-autoprop-init.md ├── csharp-7.0 │ ├── binary-literals.md │ ├── digit-separators.md │ ├── expression-bodied-everything.md │ ├── local-functions.md │ ├── out-var.md │ ├── pattern-matching.md │ ├── ref-locals-returns.md │ ├── task-types.md │ ├── throw-expression.md │ └── tuples.md ├── csharp-7.1 │ ├── README.md │ ├── async-main.md │ ├── generics-pattern-match.md │ ├── infer-tuple-names.md │ └── target-typed-default.md ├── csharp-7.2 │ ├── conditional-ref.md │ ├── leading-separator.md │ ├── non-trailing-named-arguments.md │ ├── private-protected.md │ ├── readonly-ref.md │ ├── readonly-struct.md │ ├── ref-extension-methods.md │ ├── ref-struct-and-span.md │ └── span-safety.md ├── csharp-7.3 │ ├── auto-prop-field-attrs.md │ ├── blittable.md │ ├── enum-delegate-constraints.md │ ├── expression-variables-in-initializers.md │ ├── improved-overload-candidates.md │ ├── indexing-movable-fixed-fields.md │ ├── pattern-based-fixed.md │ ├── ref-local-reassignment.md │ ├── ref-loops.md │ ├── stackalloc-array-initializers.md │ └── tuple-equality.md ├── csharp-8.0 │ ├── README.md │ ├── alternative-interpolated-verbatim.md │ ├── async-streams.md │ ├── async-using.md │ ├── constraints-in-overrides.md │ ├── constructed-unmanaged.md │ ├── default-interface-methods.md │ ├── nested-stackalloc.md │ ├── notnull-constraint.md │ ├── null-coalescing-assignment.md │ ├── nullable-reference-types-specification.md │ ├── nullable-reference-types.md │ ├── obsolete-accessor.md │ ├── patterns.md │ ├── ranges.cs │ ├── ranges.md │ ├── readonly-instance-members.md │ ├── shadowing-in-nested-functions.md │ ├── static-local-functions.md │ ├── unconstrained-null-coalescing.md │ └── using.md ├── csharp-9.0 │ ├── covariant-returns.md │ ├── extending-partial-methods.md │ ├── extension-getenumerator.md │ ├── function-pointers.md │ ├── init.md │ ├── lambda-discard-parameters.md │ ├── local-function-attributes.md │ ├── module-initializers.md │ ├── native-integers.md │ ├── nullable-constructor-analysis.md │ ├── nullable-parameter-default-value-analysis.md │ ├── nullable-reference-types-specification.md │ ├── patterns3.md │ ├── records.md │ ├── skip-localsinit.md │ ├── static-anonymous-functions.md │ ├── target-typed-conditional-expression.md │ ├── target-typed-new.md │ ├── top-level-statements.md │ ├── unconstrained-type-parameter-annotations.md │ └── variance-safety-for-static-interface-members.md ├── dictionary-expressions.md ├── enhanced-switch-statements.md ├── expand-ref.md ├── extension-operators.md ├── extensions.md ├── field-keyword.md ├── fieldof.md ├── first-class-span-types.md ├── ignored-directives.md ├── inactive │ ├── README.md │ ├── list-patterns-enumerables.md │ ├── pointer-null-coalescing.md │ └── repeated-attributes.md ├── interpolated-string-handler-argument-value.md ├── left-right-join-in-query-expressions.md ├── nominal-type-unions.md ├── null-conditional-assignment.md ├── null-conditional-await.md ├── optional-and-named-parameters-in-expression-trees.md ├── partial-events-and-constructors.md ├── pattern-variables.md ├── proposal-template.md ├── readonly-parameters.md ├── readonly-setter-calls-on-non-variables.md ├── rejected │ ├── README.md │ ├── declaration-expressions.md │ ├── discriminated-unions.md │ ├── fixed-sized-buffers.md │ ├── format.md │ ├── interpolated-string-handler-method-names.md │ ├── intptr-operators.md │ ├── intrinsics.md │ ├── nullable-enhanced-common-type.md │ ├── param-nullchecking.md │ ├── params-span.md │ ├── readonly-locals.md │ ├── records.md │ ├── recordsv2.md │ ├── self-constraint.md │ └── static-delegates.md ├── simple-lambda-parameters-with-modifiers.md ├── speclet-disclaimer.md ├── target-typed-static-member-lookup.md ├── unbound-generic-types-in-nameof.md └── user-defined-compound-assignment.md └── spec ├── LICENSE.md ├── README.md ├── arrays.md ├── attributes.md ├── basic-concepts.md ├── classes.md ├── conversions.md ├── delegates.md ├── documentation-comments.md ├── enums.md ├── exceptions.md ├── expressions.md ├── interfaces.md ├── introduction.md ├── lexical-structure.md ├── namespaces.md ├── statements.md ├── structs.md ├── types.md ├── unsafe-code.md └── variables.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @dotnet/roslyn-compiler 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Propose a language idea or ask a question 4 | url: https://github.com/dotnet/csharplang/discussions/new/choose 5 | about: Starting with discussion is the way to create a new proposal. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/docs-feedback.yml: -------------------------------------------------------------------------------- 1 | name: Learn feedback control. 2 | description: | 3 | ⛔ This template is hooked into the feedback control on the bottom of every page on the learn.microsoft.com site. It automatically fills in several fields for you. Don't use for other purposes. ⛔ 4 | assignees: 5 | - BillWagner 6 | labels: 7 | - Area-Speclets 8 | - untriaged 9 | body: 10 | - type: markdown 11 | attributes: 12 | value: "## Issue information" 13 | - type: markdown 14 | attributes: 15 | value: Select the issue type, and describe the issue in the text box below. Add as much detail as needed to help us resolve the issue. 16 | - type: dropdown 17 | id: issue-type 18 | attributes: 19 | label: Type of issue 20 | options: 21 | - Typo 22 | - Spec incorrect 23 | - Spec incomplete 24 | - Other (describe below) 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: feedback 29 | validations: 30 | required: true 31 | attributes: 32 | label: Description 33 | - type: markdown 34 | attributes: 35 | value: "## 🚧 Article information 🚧" 36 | - type: markdown 37 | attributes: 38 | value: "*Don't modify the following fields*. They are automatically filled in for you. Doing so will disconnect your issue from the affected article. *Don't edit them*." 39 | - type: input 40 | id: pageUrl 41 | validations: 42 | required: true 43 | attributes: 44 | label: Page URL 45 | - type: input 46 | id: contentSourceUrl 47 | validations: 48 | required: true 49 | attributes: 50 | label: Content source URL 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/proposal_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Create a language specification 3 | about: For proposals that have been invited by a team member. 4 | title: "[Proposal]: [FEATURE_NAME]" 5 | --- 6 | 11 | # FEATURE_NAME 12 | 13 | * Specification: Link to a filled out [proposal template](../../proposals/proposal-template.md). If not yet available, link to the PR adding the specification. 14 | * Discussion: Link to the discussion topic for this feature. 15 | 16 | ## Summary 17 | [summary]: #summary 18 | 19 | 20 | 21 | ## Design meetings 22 | 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | 3 | # Ignore temporary files 4 | ~$* 5 | *~ 6 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project has adopted the code of conduct defined by the Contributor Covenant 4 | to clarify expected behavior in our community. 5 | 6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). 7 | -------------------------------------------------------------------------------- /Communities.md: -------------------------------------------------------------------------------- 1 | **Disclaimer**: This document is maintained by the C# community and not the responsibility of the C# Language Design Team (LDT). Please do not contact the LDT for any errors in this document; however, PRs are welcome. 2 | 3 | **Channels:** 4 | 5 | - [Dotnet Discord](https://aka.ms/dotnet-discord-csharp) - github.com/dotnet discord for discussing dotnet repositories (including csharplang). 6 | 7 | [![Chat on Discord](https://discordapp.com/api/guilds/143867839282020352/widget.png)](https://aka.ms/dotnet-discord-csharp) 8 | 9 | - [C# Discord](https://aka.ms/csharp-discord) - General C# discussion not limited to the dotnet repositories. 10 | 11 | [![Chat on Discord](https://discordapp.com/api/guilds/102860784329052160/widget.png)](https://aka.ms/csharp-discord) 12 | 13 | - IRC - Any discussion related to the C# language up to the application level. 14 | 15 | [![Join the chat at https://www.irccloud.com/invite?channel=%23%23csharp&hostname=irc.freenode.net&port=6697&ssl=1](https://img.shields.io/badge/IRC-%23%23csharp-1e72ff.svg?style=flat)](https://www.irccloud.com/invite?channel=%23%23csharp&hostname=irc.freenode.net&port=6697&ssl=1) 16 | 17 | Servers: irc.freenode.net, chat.freenode.net 18 | 19 | Channel: ##csharp 20 | 21 | [![Join the chat at https://www.irccloud.com/invite?channel=%23c%23&hostname=irc.quakenet.org&port=6697&ssl=1](https://img.shields.io/badge/IRC-%23c%23-1e72ff.svg?style=flat)](https://www.irccloud.com/invite?channel=%23c%23&hostname=irc.quakenet.org&port=6697&ssl=1) 22 | 23 | Servers: irc.quakenet.org 24 | 25 | Channel: #c# 26 | 27 | Recommended IRC Clients: HexChat, mIRC. 28 | 29 | **Forums:** 30 | 31 | - [Stack Overflow](https://stackoverflow.com) 32 | 33 | Please read [this](https://stackoverflow.com/help/dont-ask) before posting. 34 | 35 | - [Reddit](https://www.reddit.com/r/csharp/) 36 | 37 | Please read [this](https://www.reddit.com/r/csharp/comments/3xn6sm/welcome_to_rcsharp_read_this_post_before) before posting. 38 | -------------------------------------------------------------------------------- /meetings/2013/README.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for 2013 2 | 3 | Overview of meetings and agendas for 2013 4 | 5 | ## Oct 7, 2013 6 | 7 | [C# Language Design Notes for Oct 7, 2013](LDM-2013-10-07.md) 8 | 9 | 1. Invariant meaning of names <*scrap the rule*> 10 | 2. Type testing expression <*can’t decide on good syntax*> 11 | 3. Local functions <*not enough scenarios*> 12 | 4. nameof operator <*yes*> 13 | 14 | [C# Language Design Notes for Oct 21, 2013](LDM-2013-10-21.md) 15 | 16 | 1. Primary Constructors <*fleshed out a few more details*> 17 | 2. Lightweight Dynamic <*we examined a much simpler approach*> 18 | 19 | ## Nov 4, 2013 20 | 21 | [C# Language Design Notes for Nov 4, 2013](LDM-2013-11-04.md) 22 | 23 | 1. Initialized and getter-only auto-properties <*details decided*> 24 | 2. Expression-bodied function members <*details decided*> 25 | 3. Lightweight dynamic <*member access model and syntax discussed*> 26 | 27 | ## Dec 16, 2013 28 | 29 | [C# Language Design Notes for Dec 16, 2013](LDM-2013-12-16.md) 30 | 31 | 1. Declaration expressions <*reaffirmed scope rules, clarified variable introduction*> 32 | 2. Semicolon operator <*reaffirmed enclosing parentheses*> 33 | 3. Lightweight dynamic member access <*decided on a syntax*> 34 | -------------------------------------------------------------------------------- /meetings/2015/LDM-2015-05-25.md: -------------------------------------------------------------------------------- 1 | # C# Design Meeting Notes for May 25, 2015 2 | 3 | Discussion for these notes can be found in https://github.com/dotnet/roslyn/issues/3912. 4 | 5 | ## Agenda 6 | 7 | Today we went through a bunch of the proposals on GitHub and triaged them for our list of features in issue #2136. Due to the vastness of the list, we needed to use *some* criterion to sort by, and though far from ideal we ordered them by number of comments, most to least. 8 | 9 | Here's where we landed, skipping things that were already "Strong interest". Some are further elaborated in sections below. 10 | 11 | 1. Method contracts <*Stay at "Some interest"*>(#119) 12 | 2. Destructible types <*Stay at "Probably never"*> (#161) 13 | 3. Params IEnumerable <*Stay at "Small but Useful*>(#36) 14 | 4. Multiple returns <*Addressed by tuples. Close.*> (#102) 15 | 5. More type inference <*Not a coherent proposal. Close*> (#17) 16 | 6. Readonly parameters and locals <*Stay at "Some interest"*>(#115) 17 | 7. Implicitly typed lambdas <*Add at "Probably never"*>(#14) 18 | 8. Immutable types <*Stay at "Some interest*>(#159) 19 | 9. Object initializers for immutable objects <*Add at "Some interest"*>(#229) 20 | 10. First item is special <*Add at "Never"*>(#131) 21 | 11. Array slices <*Keep at "Interesting but needs CLR support"*>(#120) 22 | 12. Vararg calling convention <*Merge with params IEnumerable*>(#37) 23 | 13. XML Literals <*Add to "Never"*>(#1746) 24 | 14. Local Functions <*Move to "Some interest*>(#259) 25 | 15. Covariant returns <*Stay at "Some interest*>(#357) 26 | 27 | # Params IEnumerable 28 | 29 | This needs more thinking - let's not just implement the straightforward design. There are perf issues, for instance, around implementing through the `IEnumerable` interface instead of arrays directly. 30 | 31 | # More type inference 32 | 33 | Not a coherent proposal. But even if there was one, we probably wouldn't want it in C#. 34 | 35 | # Implicitly typed lambdas 36 | 37 | These are mostly subsumed by local functions, which we'd rather do. It has some individual usefulness but not much synergy. 38 | 39 | # Object initializers for immutable objects 40 | 41 | We want to think this together with withers, not sure what form it would take. 42 | 43 | # first item in loops is special 44 | 45 | We recognize the scenario but it's not worthy of a feature. 46 | 47 | # vararg calling convention 48 | 49 | Roll it in with params IEnumerable discussion for investigation. 50 | 51 | # XML literals 52 | 53 | Never! We won't bake in a specific format. 54 | 55 | -------------------------------------------------------------------------------- /meetings/2016/LDM-2016-09-06.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Sep 6, 2016 2 | 3 | ## Agenda 4 | 5 | 1. How do we select `Deconstruct` methods? 6 | 7 | # How do we select Deconstruct methods? 8 | 9 | `(int x, var y) = p` cannot just turn into `p.Deconstruct(out int x, out var y)`, because we want it to find a `Deconstruct` method with a more specific type than `int`, e.g. `byte`. 10 | 11 | We should look only at the arity of the `Deconstruct` method. If there's more than one with the given arity, we fail. If necessary, we will then translate this into passing temporary variables to the `Deconstruct` method, instead of the ones declared in the deconstruction. E.g., if `p` has 12 | 13 | ``` C# 14 | void Deconstruct(out byte x, out byte y) ...; 15 | ``` 16 | 17 | We would translate it equivalently to: 18 | 19 | ``` c# 20 | p.Deconstruct(out byte __x, out byte __y); 21 | (int x, int y) = (__x, __y); 22 | ``` -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-01-10.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Jan 10, 2017 2 | 3 | ## Agenda 4 | 5 | - Discriminated unions via "closed" types 6 | 7 | # Discriminated unions via "closed" types 8 | 9 | There's a [proposal](https://github.com/dotnet/roslyn/issues/8729) to allow adding `closed` to an abstract type. This prevents inheriting from any other assembly, meaning that there would be a known set of derived types, all in the same assembly as the closed abstract type. This is somewhat similar to Scala's case classes. 10 | 11 | At the metadata level, this could possibly be implemented by generating an internal abstract member. In fact that member could make itself useful as a property returning a tag, so we can do efficient tag-based switching. 12 | 13 | A nice aspect is that `closed` can be added to existing hierarchies, adding a notion of completeness and protecting from "unauthorized" inheritance. 14 | 15 | Adding this to existing code may lead to completeness warnings in consuming code. 16 | 17 | In a lot of places where you switch, you don't even *want* completeness. It's almost like it's something you have to ask for at the switch site. Special syntax? 18 | 19 | "Catch all" is a problem. Often I want to have a catch all *even* as I want to be told if there's a new case. We *could* say that if there's a closed type, then you need to be complete in a switch. Which you can be with a `default`, but then you won't know if there's a new case: it's up to you. 20 | 21 | Enums: We could allow `closed` on those, and then eliminate the explicit conversion to it, as well as arithmetic. Switching could generate a default that throws, in case someone monkeyed an illegal value in there. 22 | 23 | A closed enum wouldn't get much value out of being an enum, since we don't want operators to work on them. We could consider making them not be enums from the runtime perspective. 24 | 25 | ## Conclusion 26 | 27 | An interesting approach to discriminated unions that might be a better fit with the spirit of C#. 28 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-01-11.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Jan 11, 2017 2 | 3 | *Raw notes - need cleaning up* 4 | 5 | ## Agenda 6 | 7 | - Language aspects of [compiler intrinsics](https://github.com/dotnet/roslyn/issues/11475) 8 | 9 | Intrinsics 10 | 11 | Two compiler behaviors: 12 | 1. Recognize declarations as intrinsics, and implement them 13 | 2. Enforce whichever special rules apply on call 14 | 15 | Could grow the list over time. 16 | 17 | Scenario: avoid il rewrite or inefficient impls 18 | 19 | Lets you do cross-platform libraries. 20 | 21 | This feels cheap, and limits the implact to just the compiler. 22 | 23 | Can't be abstracted out into generic methods - at least without combinatorial explosion 24 | 25 | Some might be obsoleted over time as language features ("static delegates"?) come along. 26 | 27 | Could allow optionally specifying the intrinsic name in the attribute, so you could call the method something else if you like 28 | 29 | Open question: local functions. 30 | 31 | Wouldn't emit to metadata. 32 | 33 | How supported should this be, as a language feature? Should semantic analysis understand this, and give you good live feedback? Doesn't need a lot of tooling support out of the gate; it's a feature for a very small set of 34 | 35 | 36 | 37 | 38 | ``` c# 39 | switch(...) 40 | { 41 | case string s when .... x1: 42 | case int i when .... x2 & capture x1: 43 | case 1 when ... capture x1; 44 | break 45 | 46 | case string s when .... x3: 47 | case int i when .... x4: 48 | case 1 when .... & capture something 49 | break; 50 | } 51 | ``` 52 | 53 | The code needed to be surprised by the lifetime of expression variables in case headers being the whole switch block is quite convoluted (just like this sentence). 54 | 55 | ``` c# 56 | case 1 => WriteLine(...); 57 | case 2 58 | { 59 | 60 | } 61 | 62 | case string s when (...) 63 | { 64 | ... 65 | } 66 | ``` 67 | 68 | - Broaden scope and lifetime of expr variables to whole switch block 69 | - Broaden lifetime of expr variables, but not the scope 70 | - Limit scope of variables in bodies of cases that are "new" 71 | - 72 | 73 | 74 | When there are expression variables in the case header, in the case body forbid: 75 | - ref locals 76 | - to expr variables 77 | - local functions 78 | - that capture case-section expr variables 79 | - labels 80 | - that are jumped to from other case sections 81 | 82 | Drop the subbullets for now, and maybe we can relax later 83 | 84 | 85 | Out of all these approaches, we still think expanding the lifetime (but not the scope) has the lowest risk. Fallout work is likely in the debugger, which will have a suboptimal experience in these scenarios. This work is probably puntable. 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-02-14.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Feb 14, 2017 2 | 3 | *Upcoming meeting* 4 | 5 | ## Agenda 6 | 7 | - Meet with Unity to discuss language features relevant to game developers -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-02-15.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Feb 15, 2017 2 | 3 | *Upcoming meeting* 4 | 5 | ## Agenda 6 | 7 | - Design Review -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-03-28.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Mar 28, 2017 2 | 3 | ## Agenda 4 | 5 | Design some remaining 7.1 features 6 | 7 | 1. Fix pattern matching restriction with generics 8 | 2. Better best common type 9 | 10 | 11 | # Fix pattern matching restriction with generics 12 | 13 | Today `x as T` is allowed if 14 | 15 | 1. there is a reasonable relationship between the left and right type, or 16 | 2. one of them is an open type 17 | 18 | But for the `is` operator we don't have the second. That means that we can't always replace uses of `as` followed by null check with an `is` with a type pattern. 19 | 20 | Also, the restrictions are supposed to rule out only obviously useless cases, whereas some of these are demonstrably useful. 21 | 22 | Let's allow it, look again if there are unexpected problems. 23 | 24 | 25 | # Better best common type 26 | 27 | Best common type should combine a value type with null literal to get a nullable value type. 28 | 29 | ``` c# 30 | b1 ? 1 : b2 ? null : b3 ? 2 : default; // default is 0 31 | b1 ? 1 : b2 ? default : b3 ? 2 : null; // default is null 32 | 33 | b1 ? 1 : (b2 ? null : (b3 ? 2 : default)); // default is 0 34 | b1 ? 1 : (b2 ? default : (b3 ? 2 : null)); // default is null 35 | ``` 36 | 37 | This is weird, but fine: 38 | 39 | ``` c# 40 | M(1, default, null); // int? 41 | ``` 42 | 43 | Next step is trying to spec it. It's a bit complicated. 44 | 45 | ``` c# 46 | M(myShort, myNullableInt, null); Should continue to infer int? , not short? 47 | ``` 48 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-04-11.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Apr 11, 2017 2 | 3 | ## Agenda 4 | 5 | 1. Runtime behavior of ambiguous default implementation 6 | 7 | 8 | # Runtime behavior of ambiguous default implementation 9 | 10 | The feature is intended to work when a new default-implemented member is added to an interface `I`, even when an implementing class `C` is not recompiled. So the runtime needs to know about default implementations and be able to find them. 11 | 12 | In the case of overrides, there may be diamond-hierarchy cases where the compiler knows of only one override, but one is added later to another interface. The implementations are now ambiguous, and a recompilation would cause an ambiguity, but it would seem desirable that the runtime should choose "the one the compiler knew about"; that, somehow, that knowledge would be baked in to the compiled class `C`. 13 | 14 | Starting out with these type declarations in separate assemblies: 15 | 16 | ``` c# 17 | interface I1 { void M() { Impl1 } } 18 | interface I2 : I1 { override void M() { Impl2 } } 19 | interface I3 : I1 { } 20 | class C : I2, I3 { } 21 | ``` 22 | 23 | Everyone's happy, and `C`'s implementation of `M` would unambiguously come from `I2`. 24 | 25 | Now `I3` is modified and recompiled: 26 | 27 | ``` c# 28 | interface I3 : I1 { override void M() { Impl3 } } 29 | ``` 30 | 31 | What should happen at runtime? When `C` was compiled, it "thought" everything was alright. At runtime it isn't. Can the compilation of `C` bake in a preference based on its understanding of the world at the time of compilation? Should it? 32 | 33 | It is not obvious how this would work. What if the default implementation `C` depends on is moved, deleted or overridden? Should it just be a "vague" preference in case of ambiguity, to get the runtime on the right track? 34 | 35 | This seems complicated, fragile and fraught with peril, but ending up with an ambiguity at runtime is also bad. 36 | 37 | Regardless, there will always be runtime ambiguities; "baking in" preferences would only address a subset. Two open questions: 38 | 39 | 1. Should we try to help resolve ambiguities by baking in compile time preferences? Unresolved. 40 | 2. Should we fail or pick an "arbitrary" implementation in case of inevitable ambiguities at runtime? Unresolved. Bad to error. Bad to run "arbitrary" code. 41 | 42 | We should look more deeply into what Java does here. There must be accumulated insight already on this topic. 43 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-05-16.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for May 16, 2017 2 | 3 | ## Agenda 4 | 5 | 1. Triage C# 7.1 features that didn't make it 6 | 2. Look at C# 7.2 features 7 | 3. GitHub procedure around new design notes and proposals 8 | 4. Triage of championed features 9 | 10 | 11 | # Triage C# 7.1 features that didn't make it 12 | 13 | ## Private protected 14 | 15 | Almost there, push to 7.2 for completion. 16 | 17 | ## Field-targeted attributes 18 | 19 | This is a bug fix level change, and very useful. Push to 7.2 20 | 21 | 22 | # Look at C# 7.2 features 23 | 24 | "Slicing" needs to be split into "ref structs" and "slicing syntax". 25 | 26 | Push out everything, except 27 | - things that are "in theme" - related to refs, spans, etc. 28 | - things that are almost done (field-targeted attributes, private protected) 29 | 30 | Keep everything that's in theme until we can sit with the `Span` folks and prioritize. 31 | 32 | 33 | # GitHub procedure around new design notes and proposals 34 | 35 | We should use issues as a notification mechanism for when design notes and proposals are completed. Revisions are comments on the same issue. 36 | 37 | (This has now been adopted for design notes back to Mar 15, 2017.) 38 | 39 | 40 | # Triage of championed features 41 | 42 | ## CallerArgumentExpression 43 | 44 | Push to 7.X and start process for getting the attribute in place. 45 | 46 | ## Leading and trailing digit "separators" 47 | 48 | ``` c# 49 | M(0b_1, 0x_A) 50 | ``` 51 | 52 | Very low additional value. Would probably help some code generators, and some code layout. Might accept a pull request. 53 | 54 | ## Static delegates 55 | 56 | Delegates require, generally, 2 allocations, and are crappy for interop. Static delegates are typed `IntPtr`s, essentially. 57 | `ValueAction` and `ValueFunc`. Lot of asks from CoreRT, for PInvoke etc. Of course they won't be able to close over anything, so they'd require significant language support. 58 | 59 | ## Namespace XML doc comments 60 | This is hard to take as a community contribution: it's primarily about the IDE behavior. Not all of that may even be open source today. 61 | It would also affect the rest of the ecosystem, which would now have to handle it. Need to coordinate with IDE team. 62 | 63 | ## `??` and `?.` for pointers 64 | 65 | Probably lo-pri to make this pleasant. But nothing against it. This seems suitable for up-for-grabs. 66 | 67 | The syntax should probably be `?->`. For double pointers, you're out of options! 68 | 69 | 70 | ## Non-trailing named arguments 71 | 72 | Helps selectively use parameter names for readability. Would relieve people from bending over backwards to put name-prone parameters last. Also would make it work better with params. 73 | 74 | Would need some ide work. 75 | 76 | 77 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-08-16.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Aug 16, 2017 2 | 3 | *Quote of the day:* 4 | > "It's an open question whether we go out with a bang`!`" 5 | 6 | ## Agenda 7 | 8 | 1. The null-forgiving operator 9 | 10 | 11 | # The null-forgiving operator 12 | 13 | How exactly does the null-forgiving post-fix `!` operator work? 14 | 15 | Proposal: 16 | 17 | 1. *Target typed*: `e!` implicitly converts to `T` if `e` does, but without nullability warnings 18 | - `string s = null!;` 19 | - `string s = default!` 20 | - `string s = GetNameOrNull()!;` 21 | - `List l = GetList()!;` 22 | - `List l = GetList()!;` 23 | 2. *Inherent type*: if the type of `e` is a nullable reference type `T?`, then the inherent type of `e!` is `T` 24 | - `var s = GetNameOrNull()!;` 25 | - `GetNameOrNull()!.Length;` 26 | 3. *Default expressions*: if `T` is a non-nullable reference type, then `default(T)!` suppresses the warning normally given by `default(T)` 27 | 28 | For 2, an alternative is to have a dedicated `!.` and `![...]` operator, cousins of `?.` and `?[...]`. Then you wouldn't get to factor out to a local with `var`, though. 29 | 30 | 3 is a bit of a corner case. Most people would choose to just rewrite it to something else - there are plenty of options. But `default(T)` is a good strategy for code generators, so probably worth keeping the ability to silence that warning. 31 | 32 | We could generalize `!` to silencing all nullability warnings even in subexpressions. This seems ill-motivated, though, and there's no particular expectation that you want silencing in subexpressions at the same time you want it on the overall expression. 33 | 34 | If `!` is applied in a place that yields no nullability warnings, does that lead to a warning? No. We don't want to create a new source of warnings caused by a warning-suppressing operator! There is a legit scenario, which is to clean up superfluous "!"s when a depended-upon API gets properly annotated. But this seems more the province of analyzers or similar tools. 35 | 36 | We can make `!!` an error. If you really want two consecutive bangs (we don't believe there's *any* scenario, other than swearing) you can parenthesize: `(e!)!`. 37 | 38 | An alternative is to make the type of `e!` oblivious, if we choose to embrace a notion of oblivious. That's attractive in that it makes a type for "something that doesn't yield warnings", but it's also viral - could lead to many things not being checked. It's an option to be considered in future. 39 | 40 | ## Conclusion 41 | 42 | Follow the proposal. Make `!!` an error. -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-08-21.md: -------------------------------------------------------------------------------- 1 | # C# Language Design for Aug 21, 2017 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | 6 | # Type classes 7 | 8 | Multiple implementations (ints and groups) 9 | - You can explicitly provide the type argument for an implicit type parameter 10 | - (but it might get messy) 11 | 12 | 13 | Need explicit instance 14 | - Nothing fundamental preventing a more structural approach 15 | - Two levels of inference possible: 16 | - a: explicit instance, infer members 17 | - b: implicit instance even 18 | 19 | 20 | To bridge to existing interface-based abstractions, you can just provide a very general, generic instance 21 | 22 | 23 | Need an implicit type parameter but don't use it. Maybe a bit too magical. Might be better to require dotting off of the implicit type parameter. For operators that would be nice, though. 24 | 25 | 26 | Instance members? need some syntax like extension methods, maybe, or like explicit interface implementation. 27 | 28 | 29 | Concepts can be for more than one type, so they are not always tied to a single domain type. This may be a step too far, but it does have real value: Graph algorithms that have both Node and Edge types. 30 | 31 | Main competitor, conceptually, would be something that allows for interfaces to play the role of concepts. That comes with challenges of its own, and lots of limitations. But that sort of the thing you have to justify why you're not. 32 | 33 | 34 | Could you use this to make the environment of a lambda a struct? Combined with closures as structs, passed by ref. 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-09-25.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Sep 25. 2017 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | # Ref readonly locals 6 | 7 | We have nowhere to put a ref readonly result. Ref readonly locals are like ref locals, except that they don't allow mutation of the ref'ed variable. 8 | 9 | ``` 10 | var x = a[1]; 11 | ref readonly var r = ref a[1]; 12 | ``` 13 | 14 | We could have `var` infer the `readonly` as well. It wouldn't be breaking to add later. 15 | 16 | Why do we allow the silent copying of readonly struct values in these new scenarios? Do we like that? 17 | 18 | No, but for consistency. People will need to use analyzers already to catch the existing cases. Those analyzers should just have this feature in there as well. 19 | 20 | We agree that this is a reasonable feature to have, and the design is right. 21 | 22 | Like ref locals, these aren't currently reassignable, but there's no dependence on that. We could change it later. There's then technically room for an extra `readonly` in front. 23 | 24 | For 25 | 26 | ``` c# 27 | MyRefTaker(42); 28 | MyRefTaker(ref MyRefReturner()); 29 | ref readonly int r = 42; 30 | ref readonly int r = ref MyRefReturner(); 31 | b ? 42 : MyRefReturner() 32 | 33 | return ref r; 34 | 35 | ref readonly int x = a[1]; 36 | ``` 37 | 38 | Discussion about whether the implicitness is a good thing. 39 | 40 | There are other options: require "ref" in arguments, require "in" in arguments. We still want the implicit ref in parameters. 41 | 42 | For operators, during overload resolution we ignore the refness. 43 | 44 | ## Conclusion 45 | 46 | Let's flip to requiring `ref` in argument position. `ref 42` and `ref x+y` etc are allowed. 47 | 48 | 49 | (Other small decisions) 50 | 51 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-10-02.md: -------------------------------------------------------------------------------- 1 | # Milestone philosophy 2 | 3 | 4 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 5 | 6 | 7.3 is a bucket for next steps with pattern matching. 7 | 8 | Non-exhaustive list 9 | 10 | - recursive patterns 11 | - non-null patterns 12 | - switch expression 13 | - negated if-condition 14 | 15 | 8.0 is for major language features 16 | 17 | 18 | # Discussion on how we get input 19 | 20 | We should solicit problems, not just solutions 21 | 22 | # Triage 23 | 24 | ## 945 25 | Could make it always prefer by-value as a tie-breaker. 26 | 27 | ## 933 28 | Motivating scenarios: 29 | 30 | 1. Hold on to the content variable in linked list elements 31 | 2. assign one as a default and have an if overwrite it with another 32 | 33 | Syntax! Should we be putting `ref` in front of the LHS, or just the RHS? 34 | 35 | ``` c# 36 | ref r = ref v; // or 37 | r = ref v; 38 | ``` 39 | 40 | Not requiring ref lets us: 41 | 42 | - Be more terse 43 | - Work as an expression (because no expression starts with ref) 44 | 45 | Requiring makes it syntactically clear whether you are assigning to `r` itself (in the ref space) or to the variable currently pointed to by `r` (in the value space). Also, what the hell does code mean if e.g. a ref-reassigning expression occurs as a ref or out argument? 46 | 47 | ``` c# 48 | M(out r = ref v); //What? 49 | ``` 50 | 51 | We'd just recommend parenthesizing the assignment, like we recommend everywhere else assignments are used as expressions. 52 | 53 | There's a limit which is that there's no proper default, so we'd still always require initialization, picking up the lifetime from the initializer. This is a bit painful when you want it to have global lifetime (no good default to provide). 54 | 55 | We should instead allow you to not have an initializer. We do definite assignment analysis. It has global lifetime. 56 | 57 | 58 | 59 | ``` c# 60 | ref readonly tmp = ref Get(); 61 | M(in tmp); 62 | ``` 63 | 64 | Annoying that there's sort of three different ways to talk about a `ref readonly`: `ref readonly`, `ref` and `in`. 65 | 66 | Should we switch parameter to `ref readonly`? Allow choice. 67 | 68 | No: Let's keep having only one way of doing it, and let's have that way be consistent with what you say at the call site. 69 | 70 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-10-09.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Oct 9, 2017 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | 6 | # 882 Negated if or negative patterns 7 | 8 | Three approaches 9 | 10 | 1. bang outside if condition (then should I do that on while etc, too) `if !(o is int i)` 11 | 2. negative patterns (but not very useful recursively) `not int i` 12 | 3. `is not` as an expression operator 13 | 14 | # 867 15 | 16 | Avoid some statement cliffs... 17 | 18 | Put it in X.X with a note to consider again when we have match expressions 19 | 20 | # 414 21 | 22 | There's a "there" there. 23 | 24 | We think this should be addressed, and will keep the championing issue to represent it. 25 | 26 | However, it should be different: 27 | 28 | 1. It should not be strongly tied to the `Dictionary` type, but be target typed 29 | 2. We should look at initializing immutable objects (also for object and collection initializers) 30 | 3. We already have index initializers. Are they good enough? 31 | 32 | # 973 Declaration expressions 33 | 34 | Last time, we had two issues: 35 | 36 | 1. Weren't ready to commit to scoping rules 37 | 2. Weren't sure that we could get decent error recovery on syntax 38 | 39 | 1 is dealt with. 40 | 2 was more that it was hard to show intellisense because more things were legal 41 | 42 | Scenario is introduce a local variable in expressions without having to use trivial pattern matching. Also ref. 43 | 44 | We feel like we need to spend more time with it to judge its value. 8.0 for now to trigger that discussion. 45 | 46 | # 881 and 33 47 | 48 | Fits with nullable in 8.0 49 | 50 | # 185 51 | 52 | Settle this in the 7.3 timeframe 53 | 54 | # 187 Blittable 55 | 56 | # 435 57 | 58 | # 287 59 | 60 | # 32 61 | 62 | # 125 63 | 64 | Missing, but not much ask for it 65 | 66 | # 111 67 | 68 | We would want to deal with single parameters. A problem is that discards do not shadow today, whereas identifiers do. We may want to change that. 69 | 70 | # 191 71 | 72 | Need more motivation 73 | 74 | # 190 75 | 76 | Some open design discussions 77 | 78 | # 79 | 80 | 81 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-10-16.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Oct 16, 2017 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | 6 | "Being on the same floor as SPJ is a good way to shake out difficult corner cases" 7 | 8 | 1. LINQ 9 | 2. Shapes 10 | 11 | 12 | # Applying to LINQ 13 | 14 | Mixed results. 15 | 16 | Looking for perf, and ways to do more selective specialization. 17 | 18 | ## Sum 19 | 20 | Specialized to some numeric types, but not all. 500 lines of code. In those, the loop is unspecialized too. 21 | 22 | One page of code! 23 | 24 | A new design dimension: should I use interfaces or concepts: pay for abstraction or pay for specialization 25 | 26 | Generic soup: this may be a superficial design issue, or even tooling issue. 27 | 28 | For instance, the `AssociatedType`s, other languages allow them to be retrieved by dot notation. Jeremy Siek paper "Associated Types and ...". `TColl.TEnum` etc. 29 | 30 | From experience, abstracting over enumerators tends to need associated types or higher-kinded types. 31 | 32 | Shouldn't be too discouraged by being smoked by LINQOptimizer. That one optimizes big queries, but what keeps people away from LINQ is more the death by a thousand paper cuts of using LINQ all the time. Roslyn avoids things that allocate, which today means not using LINQ. THis could be the thing that would allow it to. 33 | 34 | ## Select 35 | 36 | The return type is associated. The problem is that adding new instances can change the return type from afar, upsetting the consuming code. 37 | 38 | Improves by 2/3rds when the array specialization is used. 39 | 40 | ## SelectMany 41 | 42 | The generic type inference gets very messy here. It shows that concept inference needs to be interleaved with type inference in a way that we are still only loosely grasping. 43 | 44 | This is a place where LINQ allocates a lot, whereas this allocates hardly anything. We go at .75 the time even unspecialized. Also, the specialized version is twice as fast as the unspecialized. 45 | 46 | It shows that if you open up for specializations to be plopped in, there's quite a lot to gain. 47 | 48 | ## Conclusion 49 | 50 | Some promise on optimization. Pinches of salt here and there. The approach definitely seems to have promise. 51 | 52 | More tests to do. 53 | 54 | 55 | # Shapes 56 | 57 | Concepts can tie in to the richness of expression in C# around different kinds of operations (operators, conversions, constructors...) 58 | 59 | Interesting to consider whether there's more of a specialization relationship between concepts and instances, rather than a type/instance relationship. 60 | 61 | If this went further, there's a very large laundry list. 62 | 63 | 64 | 65 | 66 | 67 | 68 | # Conclusion 69 | 70 | We *really* would like to be able to do the post-hoc implementation of concepts. This 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-10-25.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Oct 25, 2017 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | 6 | 7 | ## #98 8 | 9 | ## 34 and 35 10 | 11 | 34 should bot be concurrent safe, just like the other compound assignment. 12 | 13 | Bundle with 8.0, but could push out. Seems to align with nullable reference types 14 | # 32 15 | 16 | Reconcile 32 with 1020 17 | 18 | 19 | Criteria: 20 | 21 | - Loose ends 22 | - External expectation 23 | 24 | # ref as iteration variable 25 | 26 | Not currently allowed, should probably have a proposal (Andy) 27 | 28 | # 185 keep in 3 to prioritize 29 | 30 | # 45 31 | 32 | Push out to 8.0 for realism, but still prioritize design time 33 | 34 | # 933, 1046, and uninitialized ref local 35 | 36 | These should happen together in 7.3 37 | 38 | # 111 Punt to 8.X 39 | 40 | # 1020 946 945 keep 41 | 42 | # 882 pattern-related, goto 8.0 43 | 44 | # 435 45 | Keep in 7.3, see if we can settle design 46 | 47 | # 190 48 | 49 | Relatively obvious design, with some gnarly bits (dynamic, conversion) 50 | 51 | Usability gap with tuples let's keep it. 52 | 53 | # 189 54 | 55 | Let is more important than from. It lets you use out variables 56 | 57 | ``` c# 58 | from s in strings 59 | let t = (b: int.TryParse(out var n), n) 60 | where t.b 61 | select t.n 62 | ``` 63 | Could be 64 | ``` c# 65 | from s in strings 66 | let (b, i) = (int.TryParse(out var n), n) 67 | where b 68 | select i 69 | ``` 70 | 71 | There's a bit of design work, especially if we also want the from clause. 72 | 73 | We could allow out vars but not the deconstruction, and it would still be useful. 74 | 75 | Could save dec for later. It's actually orthogonal. 76 | 77 | Action: 78 | 79 | Carve out deconstruction, push to 8.X 80 | 81 | # 187 82 | 83 | On the brink, but keeping for now; need to be convinced of value 84 | 85 | # 185 86 | 87 | Keep pushing on it, got to get the train going on `Range` 88 | 89 | `x..y` does new Range(x, y) or Range.Create(x, y) 90 | 91 | Consider whether it should be a new kind of operator instead. 92 | 93 | # 104 94 | 95 | Micro-feature: Just allow `System.Enum` as a constraint 96 | Mini-feature: allow `enum` as a constraint, translate to `System.Enum, struct` 97 | 98 | Keep this in, but it is very cuttable. 99 | 100 | # 98 101 | 102 | It's a zero-conceptual-overhead feature. 103 | 104 | Original designers left in space between meanings for a purpose. But that's not so compelling to us anymore. 105 | 106 | Because it touches overload resolution, it might be better aligned with a .0 release. But we're not compelled by that. 107 | 108 | Let's keep it, but again, it's cuttable. 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-11-06.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Nov 6, 2017 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | # Roslyn 20870 6 | 7 | Protecting the client from unintended dependencies. But also protects from servicing. Today people going through reflection *know* they're being bad. Would this give enough sense that they are doing something special. 8 | 9 | It would make consumers lazy about contacting the API owner about things they need exposed. 10 | 11 | It would be an arms race - we would want the `IgnoreIgnore...` attribute to *really* protect things. 12 | 13 | People will still have expectations about dependencies even if it was "their own fault" by using this attribute. 14 | 15 | ## Conclusion 16 | Too risky/fishy in too many ways. 17 | 18 | 19 | # Roslyn 17310 20 | 21 | There is no good language level solution right now. This is better addressed with an analyzer, which can know specifically about SpinLock (for instance). 22 | 23 | In time, when readonly struct declarations are added, as well as maybe the ability to declare individual struct members as readonly, *then* maybe we could start warn. 24 | 25 | ## Conclusion 26 | 27 | Not at the language level 28 | 29 | 30 | # Roslyn 20450 31 | 32 | We have sympathy. It feels like a corner that's cut. But it's quite expensive to implement, and has semantic dark corners (`List<>.First.Foo`). 33 | 34 | ## Conclusion 35 | 36 | Not now. 37 | 38 | 39 | # Roslyn 20015 40 | 41 | When default-expressions are constant (according to the language) this is not interesting expressiveness - there's a literal you can use. 42 | 43 | When they are *not* it gets a bit more interesting - you might want to check that your custom struct is zero-initialized. But you can do that with equality. Even in recursive scenarios, you can just `var`-pattern it and check in `when` or `&&`. 44 | 45 | Additionally there is some concern about the target type being clear enough for the `default` expression. 46 | 47 | ## Conclusion 48 | 49 | No. 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /meetings/2017/LDM-2017-11-29.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Nov 29, 2017 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | # Match expression 6 | 7 | Current proposal: 8 | 9 | - Infix vs prefix `switch` 10 | - `switch` vs `match` 11 | - curlies or parens for body 12 | - `case` or not 13 | - arrows? 14 | - discards or defaults? 15 | - also need to remember when clauses 16 | 17 | If it's too similar to switch statements, then it sets certain expectations. If it's too different, it's not utilizing existing intuition. 18 | 19 | Should it be a verb/command? Not many expression keywords are that (`select` is an exception, though). 20 | 21 | `case` is heavyweight, but helps visually separate the issues. 22 | 23 | ``` c# 24 | state = (state, action) switch ( 25 | (DoorState.Closed, Action.Open) => DoorState.Opened, 26 | (DoorState.Opened, Action.Close) => DoorState.Closed, 27 | (DoorState.Closed, Action.Lock) => DoorState.Locked, 28 | (DoorState.Locked, Action.Unlock) => DoorState.Closed, 29 | _ => state); 30 | 31 | state = match (state, action) 32 | { 33 | (DoorState.Closed, Action.Open) => DoorState.Opened, 34 | (DoorState.Opened, Action.Close) => DoorState.Closed, 35 | (DoorState.Closed, Action.Lock) => DoorState.Locked, 36 | (DoorState.Locked, Action.Unlock) => DoorState.Closed, 37 | _ => state 38 | }; 39 | 40 | state = switch (state, action) 41 | { 42 | case (DoorState.Closed, Action.Open): DoorState.Opened 43 | case (DoorState.Opened, Action.Close): DoorState.Closed 44 | case (DoorState.Closed, Action.Lock): DoorState.Locked 45 | case (DoorState.Locked, Action.Unlock): DoorState.Closed 46 | case _: state 47 | }; 48 | ``` 49 | 50 | The last one is subject to ambiguity-like situations between expression and statement `switch`. 51 | 52 | We should also consider nesting of match expressions. 53 | 54 | No matter what syntax we choose, we'll get requests for doing more things in expressions. We can live with that. 55 | 56 | Parens look too much like a list of *expressions*. 57 | 58 | Arrows make it look like lambda expressions. 59 | 60 | ## Decisions 61 | 62 | We agree that we will not use the keyword `default`. You can use `_`, and in the rare case where that's defined, you can use `var _`. 63 | 64 | We like curly braces for the grouping. 65 | 66 | The rest is up in the air. We'll stay with the first version for now in the prototype, other than the curly braces. 67 | 68 | 69 | 70 | # Where and when can identifier appear? 71 | 72 | 73 | 74 | # Syntax for property patterns 75 | 76 | Not urgent 77 | 78 | ``` c# 79 | 80 | ``` -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-01-10.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Jan 10, 2018 2 | 3 | ## Agenda 4 | 5 | 1. Ranges and endpoint types 6 | 7 | 8 | # Ranges and endpoint types 9 | Wouldn't it be nice to have a range type that work on any comparable? Possibly, but we're not eager to solve this right now. 10 | 11 | We need to believe that our future selves can extend the language with some form of target typing, for instance. There's a burden on them (us) to be able to do that without a compat break (silent semantic change), e.g.: There's a type in the future that has conversions so that it would work one way in 7.3 and a different way in the future. 12 | 13 | We probably want `..(int, int)` and `..(long, long)`. We want to treat those as usual operators, so they have to allow user defined conversions of the end points. We could consider blocking off normal conversions of the operands, but that's extremely distasteful. 14 | 15 | So first tentative decision: There's `Range` (for ints) and `LongRange`. The `..` operators are built-in. There's an implicit conversion one way, and an explicit the other, also both built-in. 16 | -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-02-05.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Feb 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | Index could be a type 6 | 7 | Then it's about syntax of how to express an Index that's either n from front or n from back. 8 | 9 | How important is "from end"? It's definitely convenient, but its expressiveness is probably not super important. 10 | 11 | Lots of problems with using "-", with overload resolution etc. 12 | 13 | Let's use "^" as a strawman. That takes away some of the ambiguity. 14 | 15 | There's still a question as to how an overloadable "^" would work in the future. It would be a unary operator that returns something different than it takes. How would it be found, if it lives on the result type? There's target typing there, but it may not have a target type, or that may in turn come from overloaded operators. It would have to be handled similarly to conversion in some ways. 16 | 17 | A crazy idea: Use the existing `~` operator! It creates negative numbers, yes, but don't think of them as such. Think of them as integers from end. `~0` is `-1`, `~1` is `-2` etc. This is intriguing, because we'd need *no* extra language support, and just have a convention. 18 | 19 | Quite weird though! -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-02-07.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Feb 7, 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | # Tuple equality 6 | 7 | We want to make it so that the `==` operator is delegated to the elements, but the choice of `&` operator shouldn't be up to the elements. 8 | 9 | We can't think of this in terms of a user-defined `==` on the `ValueTuple<...>` overloads, since those don't have access to the specific `==` implementations of the type arguments. 10 | 11 | 1. Same as `(tempA == tempC) && (tempB == tempD)`, taking whatever `&` operator eventually gets used. 12 | 2. Same as `(bool)(tempA == tempC) && (bool)(tempB == tempD)` but only when there is an implicit conversion to `bool` 13 | 2a. Same as 2 or `!(tempA == tempC).false && !(tempB == tempD).false`, so there are two ways to make the individual comparisons `bool` 14 | 15 | We want to do 2a, so that we make every effort to turn the result of each comparison into bool. For `==` we would use the `false` operator, for `!=` we will use the true operator. But the `&` and `|` are applied to booleans. 16 | 17 | For dynamic, let's look at what `if` does and probably do the same. 18 | 19 | 20 | # The fixed statement 21 | 22 | We're adding support for a type to have a special method that returns a pinned ref. 23 | 24 | ## Copy? 25 | 26 | Should that special method be executed on a copy or on an original l-value? We don't see good reasons to. 27 | - The method might want to change the state for the benefit of a future `fixed` or otherwise 28 | - Wasteful to copy big struct 29 | 30 | ## Generics 31 | 32 | We need to know if it's a struct or a class, to decide whether to copy (for the null check) or not (to preserve mutations in a struct). 33 | 34 | We already solved this for `?.`. We can emit a check for whether the type is a reference type (check whether its default is null), and the JIT specializes. 35 | 36 | ## Nullable 37 | 38 | No lifting. You can do your own if you really want, but there is no way (for the compiler or user) to expose the value itself without copying. If you want to pin an specific nullable type you can, as long as an extension method is provided for it. 39 | 40 | ## Ref extension methods 41 | 42 | Allow? Yes, same as for ref extension methods in general: Has to be called on a mutable l-value. For `in`, anything is fine. 43 | 44 | ## Name of method 45 | 46 | `GetPinnableReference` is weird enough; we don't have to put "Dangerous" or something in the name. 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-02-21.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Feb 21, 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | 6 | ## Agenda 7 | 8 | Various big and small issues around nullable reference types, preparing for upcoming prototypes 9 | 10 | 11 | # How are explicit casts interpreted? 12 | 13 | ``` c# 14 | (object)null // object?, with warning 15 | (object?)string.Empty // object 16 | (IEnumerable)new[]{string.Empty} // IEnumerable 17 | (IComparer)Comparer.Default // IComparer, with warning 18 | ``` 19 | 20 | For the top two, there are two approaches you can think of: 21 | 22 | - nullability should be inferred from the expression 23 | - the cast represents an intent and we should honor it 24 | 25 | It's to some degree a tension between existing code or the right design for new code. 26 | 27 | If we were to infer nullability (rather than take it from the type), would nullability problems always be caught later on? 28 | 29 | ``` c# 30 | object o = ...; 31 | var o = (object)...; 32 | 33 | class X { object[] o; } 34 | ``` 35 | 36 | If we make it more lax, then there's more of a disconnect between top-level nullability and nested nullability. 37 | 38 | If we think of `?` not so much as a type thing but an observation on what's there, it doesn't seem so onerous to have it tracked locally. 39 | 40 | Another approach: Have it be a different warning. Then you can switch it off separately, for legacy purposes. 41 | 42 | For the casts: 43 | 44 | 45 | ``` c# 46 | (string)null; // A 47 | M((string)null);// B 48 | M((string?)x); // C 49 | M((string?)F()) // D - F is unannotated, and I want to impose my understanding of what it is 50 | M((string)F()) // E - F is unannotated, and I want to impose my understanding of what it is 51 | ``` 52 | 53 | In C you want to treat the argument as may-be-null, regardless of what is in x. 54 | In B you could have a warning that is off in legacy code 55 | 56 | Assume M is generic, and we make type inference based on arguments. Then D and E both make sense - they influence the result type of M, maybe. We shouldn't wave these off, but they are in some sense separable. 57 | 58 | In the prototype we could give you the choice. We could have it on by default, and the warning could tell you how to turn it off. 59 | 60 | C is either useless, or it means "forget inferred nullability". And it won't occur in old code. 61 | 62 | Let's expand B: 63 | 64 | ``` c# 65 | M((string)y); // 66 | ``` 67 | 68 | Say this is legacy, and now M gets upgraded to take `string?`. And `y` is now possibly null. The warning on `(string)y` could be one of those that is turned off for legacy purposes. 69 | 70 | Between two options: 71 | 72 | A: locals are implicitly nullable 73 | B: locals need explicit annotations like everything else, there's a concession to legacy 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-02-28.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Feb 28, 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | Parameters: Value parameters can be treated like locals, but we may not want to. Ref and out parameters need to be guarded by non-W warnings. 6 | 7 | Is it a problem that this can lead to two related warnings? Maybe a little bit, but it's actually mostly good. You can address the declaration of s2 in three different ways: 8 | 9 | * Make ns non-null before assigning 10 | * Put a question mark on s2 11 | * Turn of W warnings 12 | Would be weird if that last one introduced another warning! 13 | 14 | Type inference: 15 | 16 | We could have `var` always have `?`. 17 | 18 | ``` c# 19 | static T[] MakeStack(T element) 20 | { 21 | 22 | } 23 | static int GetLengthOfMiddleName(Person p) 24 | { 25 | string? middleName = p.MiddleName; 26 | 27 | //return middleName.Length; 28 | if (middleName is null) return 0; 29 | var stack = MakeStack(middleName); // infer string[] or string?[] 30 | } 31 | 32 | 33 | bool b = false; 34 | string s = null; // suppressible 35 | var s2 = 36 | //(b ? s : s); 37 | Choose(b, s, s); 38 | var l = s2.Length; // not suppressible 39 | 40 | ``` 41 | 42 | Should we have type inference depend on the declared or the flowed type state? We reiterated that discussion, but conclude (again) that it's the null state that counts. This maximally helps avoid unnecessary warnings on legacy code. 43 | 44 | ## Cast and non-null 45 | 46 | ``` c# 47 | var s1 = "Hello"; // But I want to assign null later 48 | var s2 = (string?)"Hello"; // Either disallowed, makes no difference or forgets null state 49 | var? s3 = "Hello"; // Nullable but keeps the null state 50 | ``` 51 | 52 | So `var?` would be more useful than casts for `var` scenarios (because you are declaring a variable whose null state matters later). For generic arguments it doesn't matter to keep the flow state, so `(string?)` cast works fine. 53 | 54 | It's a little weird that `s2` and `s3` don't work quite the same way. They do today. 55 | 56 | Still, as a plan of record let's do this. 57 | 58 | So we keep the casts, and tentatively keep `var?`. 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-03-28.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for Mar 28, 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | Ranges 6 | 7 | # Shipping a prototype 8 | 9 | We would like to ship a prototype of ranges, in order to get feedback and settle the remaining decisions. 10 | 11 | We would need to offer the Range type, maybe as a NuGet. 12 | 13 | But it would also be nice to offer range-enhanced other types, like `Span` and maybe arrays. 14 | 15 | Maybe the compiler can fake out special indexers in the prototype. Or we also add extension indexers. 16 | 17 | Tying it to revs of .NET Core previews may be too sluggish, and fraught with dependencies. 18 | 19 | Or we create a wrapper type for Spans with the extra behavior, and smooth over the edges as best we can (implicit conversions etc) 20 | 21 | ## Conclusion 22 | 23 | Let's do: 24 | 25 | 1. A temporary "language feature" that's extension indexers based on method names 26 | 2. Range support in the language 27 | 3. A preview NuGet package with `Range`, associated types and "extension indexers" on known types 28 | 29 | 30 | # Which feature? 31 | 32 | We have two options: 33 | 34 | 1. Do like Python: just live with "0 from end" not being expressible as a number; it's a special case 35 | 2. Add Index and ^ 36 | 37 | The first one is the more restrictive, and also the cheaper one (from both work and number of abstractions). This will help us understand whether people need the extra. 38 | 39 | But not supporting "from end" is too restrictive; we have very good reason to believe people need that. 40 | 41 | 42 | # Nested stackalloc 43 | 44 | Issue #1412, trivial to implement in 8.0, where the stack-spilling machinery is there anyway for pattern matching. 45 | 46 | 47 | # Exhaustiveness in switch expressions 48 | 49 | Should non-exhaustiveness be an error or a warning? If warning, what should happen at runtime? 50 | 51 | For now, it's a warning, and if you get there we throw a new exception type for this. 52 | 53 | -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-04-02.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Review Apr 2, 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | 6 | # C# 8.0 7 | 8 | Tag with needs runtime support or ecosystem support 9 | Process: make it more clear where we are. Help people understand when beating on a feature would be wasting their time. 10 | 11 | # Nullable 12 | 13 | Make sure we work backwards to understand how long it takes to build the whole experience. 14 | 15 | ## Dotted names 16 | 17 | We probably have a good level of invalidation. 18 | 19 | ## Type strengthening 20 | 21 | Based on null state and `!`. Should definitely keep that. 22 | 23 | ## ! 24 | 25 | Because `!` only applies "right here", it is ok to also silence warnings recursively. But we should not consider automatically flowing `!` on the given execution path then, because you may not always want to silence all warnings on the variable subsequently. 26 | 27 | ## Unannotated assemblies 28 | 29 | Maybe there should be a warning that you are referencing unannotated assemblies. 30 | 31 | ## Tracking non-null variables and "W" warnings 32 | 33 | Understand the motivation. This is ok. 34 | 35 | ## Type parameters 36 | 37 | Unconstrained may be either nullable or nonnullable, so we have to be defensive. That's quite restrictive, but probably right. 38 | 39 | ## Structural relationships 40 | 41 | In TypeScript there are more type relationships because of structural types. We don't even get to first base here. 42 | 43 | # Ranges 44 | 45 | ## Open 46 | 47 | Sure about syntax? Should there be `*` instead? 48 | 49 | ## From end 50 | 51 | Indexing from end is probably more common in Python than any ranges at all! Cutting that off with `-x` syntax is a shame. 52 | 53 | If we weren't doing `^`, just do ranges with positive numbers. Solve the "from end" problem in general or not at all. 54 | 55 | ## Conclusion 56 | 57 | If indexing and multiple dimensions are in the core syntax, might as well do the whole enchilada. Optimize in compiler when using `^` on arrays and strings. 58 | 59 | 60 | -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-05-23.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for May 23, 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | # Working with data 6 | 7 | Collections of data with heterogeneous types. 8 | 9 | It's *not* objects, but decoupled from operations. 10 | 11 | - tuples 12 | - anonymous types 13 | - classes 14 | 15 | All have a mutability issue, just different ways. 16 | 17 | Modeling enumerated types is complex and doesn't provide exhaustiveness. 18 | 19 | Also, you cannot efficiently switch over different types. You do tricks like visitors, abstract kind properties, etc. Performance, correctness and succinctness are all in conflict. Type patterns help, because they look good, but they are still not as efficient or as safe as they could be. 20 | 21 | Technically speaking, mutability and value equality are a dangerous combo on classes. If the object mutates, its equality and hashcode change, meaning you could lose track of them in dictionaries, etc. 22 | 23 | On the other hand, C# is mutable by default: should we bend over backwards to not support this combo? 24 | 25 | Object initializers aren't strictly necessary, but they jive well with `with` expressions, give a less positional view. 26 | 27 | Object initializers are really popular today, in that they are used a lot. But it's unclear whether they are because the declaration site doesn't provide constructors, and instead do the "easy" thing of just offering auto-properties. 28 | 29 | Withers: we keep talking about them for readonly data, but they might very well be useful on mutable data as well. 30 | 31 | The "data classes" proposal puts weight on *not* being positional. It could even reorder members alphabetically in generated positional constructs such as constructors. 32 | 33 | Separately, there is an idea of "named tuples". These are what have previously been proposed as "records". These are an evolution story for tuples. 34 | 35 | This may be an overload of concepts. It may be that we can view them as aspects of the same feature; one may be an evolution of the other. 36 | 37 | Discriminated syntax: Enum classes. Starts very simple, probably has ways of letting you grow up. That gets messy though, with the nesting, but we could use partial to separate things. 38 | 39 | Kind fields must necessarily be unspeakable, and discoverable only by the compiler. Otherwise they can't be efficient. 40 | 41 | Records and data classes are extensions of existing constructs. Enum classes are more of a new concept. 42 | 43 | We kind of agree on the simple cases. It's how they grow up and fit into the existing world that's fraught with questions. 44 | 45 | Interestingly, you sometimes want your "enums" *not* to be exhaustive. This is the case when you expect it to evolve with more cases. 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-05-30.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for May 30, 2018 2 | 3 | ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** 4 | 5 | # Annotating parts of a project 6 | 7 | Roslyn starts out with about 2000 warnings. We may want to support nullable annotations for only a part of a project, so that you can gradually ease into them. 8 | 9 | This touches on a core question: Are there separate opt-ins for *consuming* nullability (give me warnings please) and *producing* nullability (consider unannotated reference types to be non-nullable; "URTANN"). 10 | 11 | If we have a scoped "URTANN", then turning on warnings for the whole file would still have limited impact, until annotations start becoming abundant. 12 | 13 | But we may also want to consider warnings to be turned on in a scoped way, at a certain granularity. Source files? Fine grained program elements? It might be better not having this, though, as it comes with the risk of introducing more problems (through annotation), without discovering it (because the consumption has warnings off). 14 | 15 | ``` c# 16 | T M(string s) => M2(s); // No warning because s is oblivious 17 | 18 | [URTANN] 19 | T M2(string s) => ... 20 | ``` 21 | 22 | The opt-in to warnings could be a "fake" error code that represents a category. We may not need a brand new dedicated command line option, but we're willing to go there. 23 | 24 | 1. We agree that we are comfortable (for now at least) in opting in to the warnings at the whole project level only 25 | 2. We agree that there should be a separate mechanism for opting in/out of non-null annotations (URTANN) 26 | 3. We agree that URTANN should be attribute-based, and able to be applied (or unapplied, with a `false` argument) at multiple levels of program elements 27 | 28 | Decision: 29 | 30 | Let's have `URTANN(true)` implicit by default, unless you have another module-level URTANN. We can maybe auto-generate it if you don't have it already. It should be called `NonNullTypesAttribute(bool)`. -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-08-22.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for August 22, 2018 2 | 3 | # Agenda 4 | 5 | 1. Target-typed new 6 | 1. Clarification on constraints with nullable reference types enabled 7 | 8 | # Discussion 9 | 10 | ## Target-typed new 11 | 12 | Proposal: https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md 13 | 14 | *Question: Should target-typed `new` be allowed for tuple types?* 15 | 16 | We currently don't allow the constructor syntax `new (int, int)(0, 0)`. 17 | Should we allow `(int, int) t = new(0, 0)`? Would this mean the same thing as 18 | a tuple literal, or a call to a constructor on System.ValueTuple? This would 19 | also expose some of the differences between ValueTuple and tuple types, in 20 | that there is no constructor for a tuple type with greater than 7 elements. 21 | 22 | Decision: Let's allow it, as long as that doesn't require a lot of extra 23 | work. The meaning would be to call the underlying System.ValueTuple 24 | constructors. This would expose differences in tuples with a lot of elements, 25 | but this seems like a very rare and unimportant case. 26 | 27 | *Question: Allow `throw new()`? It would convert to bare `Exception` by the spec.* 28 | 29 | Decision: Disallow. Fundamentally, we don't like this stylistically. 30 | 31 | *Question: Allow `new()` with user-defined comparison and arithmetic operators?* 32 | 33 | Decision: Allow. 34 | 35 | 36 | ## Generic constraints with nullable reference types 37 | 38 | *Question: In the following snippet, is `U` a non-nullable reference type?* 39 | 40 | ```C# 41 | void M() where T : class, U : T` {} 42 | ``` 43 | 44 | Answer: Yes 45 | 46 | *Question: In the following snippet, is `I` a non-nullable reference type?* 47 | 48 | ```C# 49 | interface I {} 50 | void M() where T : I {} 51 | ``` 52 | 53 | Answer: Yes 54 | 55 | *Q: Do we want to warn for redundant constraints?* 56 | 57 | A: We don't currently. Let's stay with that decision for now. -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-09-05.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Notes for September 5, 2018 2 | 3 | ## Agenda 4 | 5 | 1. Index operator: is it a unary operator? 6 | 1. Compiler intrinsics 7 | 8 | # Discussion 9 | 10 | ## Index operator 11 | 12 | There are multiple questions here: 13 | 14 | 1. Is the operator syntactically a unary operator? 15 | 1. Is it a user-definable operator? 16 | 1. Does it have the same precedence as other unary operators? 17 | 1. Do members which do not exist implicitly exist anyway as an intrinsic? 18 | 1. Does it have overloads? Is `^^1` allowed? That would imply that there's an 19 | overload which takes an index. 20 | 21 | Follow-up: is `..` a binary operator? 22 | 23 | **Conclusion** 24 | 25 | Agreed that it's syntactically a unary operator. Also agreed that it is a 26 | semantically treated as a unary operator that it is not user-definable. Right 27 | now, we don't see a great need to add a second overload. There is a single 28 | overload for `int`. 29 | 30 | We're not strictly defining `..` as a binary operator right now. It has its 31 | own syntactic form. 32 | 33 | Also, we're renaming '^' to the "hat" operator. 34 | 35 | ## Compiler intrinsics 36 | 37 | Proposal: https://github.com/dotnet/csharplang/blob/master/proposals/intrinsics.md 38 | 39 | There is contention between using `void*` and some stronger typing, either a 40 | delegate or some kind of function pointer syntax. The benefit of using a 41 | pointer type is that it is always unsafe, which this feature requires if 42 | there are no allocations (because an appdomain could unload and cause the 43 | invocation to point to arbitrary memory). 44 | 45 | For `calli`, there's a worry about moving the typing from the point of 46 | retrieving a function pointer to the declaration of the target and calling 47 | convention. The `extern` declaration, specifically, is disliked. 48 | 49 | Does this only work for managed code or also for native code? Do we have to 50 | care about the calling convention? 51 | 52 | **Conclusion** 53 | 54 | We'd probably be willing to accept this in some form. We think the current 55 | proposal needs some work. 56 | 57 | Some thoughts/suggestions: 58 | 59 | 1. Don't allow instance `&receiver.M` form -- only types for instance methods 60 | e.g., `&TypeName.M`. 61 | 1. Drop the separate declaration for the `calli` invocation. A special calling 62 | form like `_calli_stdcall(args, f)` is suggested. We don't like signature 63 | being declared somewhere other than the method definition or at the call site. 64 | 1. Would like the calling convention, if used, present at the call site. -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-10-10.md: -------------------------------------------------------------------------------- 1 | 2 | # C# Language Design Notes for Oct 10, 2018 3 | 4 | _QOTD: C# has a long and proud tradition of being oblivious_ 5 | 6 | ## Agenda 7 | 8 | 1. Pattern matching open questions 9 | 10 | ## Discussion 11 | 12 | All questions are in [this issue](https://github.com/dotnet/csharplang/issues/1054) 13 | 14 | ### Short discard diagnostics 15 | 16 | **Conclusion** 17 | 18 | We've taken breaking changes like this before, but there's more risk to 19 | this one because this code is legal all the way back to C# 1.0. This will 20 | not be an error -- an underscore in a case block with a constant `_` in 21 | scope will match the constant. A warning wave warning should be added 22 | to make matching a constant named `_` a warning. 23 | 24 | ### Nullable reference types vs switch analysis 25 | 26 | In general, the nullable analysis computes very similar information to 27 | switch exhaustiveness. It would be strange if the switch produced 28 | information contrary to the nullable analysis. There are some fundamental 29 | language semantic problems with making switch (and pattern) exhaustiveness 30 | and nullable analysis depend on each other. One possibility may be to 31 | perform the analysis for both of these situations simultaneously. We don't 32 | think that the exhaustiveness analysis doesn't affect the nullable analysis 33 | directly. Alternatively, we can phrase exhaustiveness as exclusive of 34 | nullable reference types and let the null analysis handle switch 35 | exhaustiveness for null specifically. Nullable value types would be handled 36 | as part of traditional exhaustiveness. 37 | 38 | **Conclusion** 39 | 40 | Let's explore the separation of exhaustiveness between null and non-null, st. 41 | all exhaustiveness warnings do not consider null, and warnings related to null 42 | are delayed until nullable analysis. 43 | 44 | Also, regardless of whether or not we generate a warning for the following case, 45 | `i` is not definitely assigned at the end: 46 | 47 | ```C# 48 | int i; 49 | switch (s) 50 | { 51 | case string t: i = 0; break; 52 | } 53 | Console.WriteLine(i); // is i definitely assigned? 54 | ``` 55 | 56 | ### Permit optionally omitting the pattern on the last branch of switch expr 57 | 58 | **Conclusion** 59 | 60 | Rejected. 61 | 62 | ### Should exhaustiveness affect definite assignment? 63 | 64 | **Conclusion** 65 | 66 | Confirmed the current behavior. 67 | 68 | ### Switch expression as statement expression 69 | 70 | **Conclusion** 71 | 72 | We like it. Not sure it will make it for C# 8.0. 73 | 74 | ### Single-element positional deconstruction 75 | 76 | **Conclusion** 77 | 78 | We need to think about 1-tuples again. -------------------------------------------------------------------------------- /meetings/2018/LDM-2018-10-31.md: -------------------------------------------------------------------------------- 1 | 2 | # C# Design Review Notes for Oct 31, 2018 3 | 4 | This was a review with the full design team (including Anders) to see how the 5 | whole release is shaping out. 6 | 7 | ## Discussion 8 | 9 | ### Nullable 10 | 11 | #### Flow analysis to turn a non-nullable type to nullable 12 | 13 | The question is whether flow analysis can cause types to become nullable if a 14 | value of non-nullable type is compared to null. 15 | 16 | ```C# 17 | void M(string x) 18 | { 19 | if (x == null) 20 | { 21 | // is x now treated as ‘string?’ here? 22 | } 23 | } 24 | ``` 25 | 26 | This is an issue that TypeScript has dealt with. There's some worry that most 27 | of the warnings will be produced not at the place with the problem. We should 28 | be careful that we're not going to annoy the user. 29 | 30 | #### Flow analysis and refactoring 31 | 32 | Flow analysis constrains refactoring because something may be tested null by 33 | flow analysis, but if you pass to a new method, the flow analysis is lost. For 34 | example: 35 | 36 | ```C# 37 | class C 38 | { 39 | string? Prop1 { get; } 40 | string? Prop2 { get; } 41 | } 42 | 43 | class C2 44 | { 45 | void M1(C c) 46 | { 47 | if (c.Prop1 != null && c.Prop2 != null) 48 | { 49 | M2(c); 50 | } 51 | } 52 | 53 | void M2(C c) 54 | { 55 | // The null checking from M1 is lost here and M2 has to 56 | // check again for null to avoid a warning 57 | c.Prop1.Equals(...) 58 | } 59 | } 60 | ``` 61 | 62 | #### `!` on parameters 63 | 64 | Very different behavior depending on where `!` appears -- maybe too many 65 | meanings. 66 | 67 | #### Treatment of lambdas 68 | 69 | For 70 | 71 | ```C# 72 | void M() 73 | { 74 | int? x = null; 75 | Action a = () => x = 0; 76 | a(); 77 | // What's the null state of `x` here? 78 | } 79 | ``` 80 | 81 | Treating the delegate conversion as executing the method is unsafe, but 82 | not doing so is conservative and will warn on valid checking. TypeScript 83 | has also hit this and there's no easy answer. -------------------------------------------------------------------------------- /meetings/2019/LDM-2019-01-16.md: -------------------------------------------------------------------------------- 1 | 2 | # C# Language Design Notes for Jan. 16th, 2019 3 | 4 | ## Agenda 5 | 6 | 1. Shadowing in lambdas 7 | 2. pattern-based disposal in `await foreach` 8 | 9 | ## Discussion 10 | 11 | ### Shadowing in nested functions 12 | 13 | *Q: Allow shadowing for all lambdas as well?* 14 | 15 | **A**: Yes. 16 | 17 | *Q: Allow shadowing with range variables in LINQ queries?* 18 | 19 | ```C# 20 | // char c; 21 | var q = from c in s 22 | from c2 in s 23 | where c != ' ' 24 | select c; 25 | var q2 = s 26 | .SelectMany(c => s, (c, c2) => new { c, c2 }) 27 | .Where(_x => _x.c != ' ') 28 | .Select(_x => _x.c); 29 | ``` 30 | 31 | `c` and `c2` can't be named the same because they are equivalent to two 32 | parameters being named the same. However, should the new `c` be able to 33 | shadow the local `c`? 34 | 35 | **A**: Let's look at the implementation and decide based on the complexity. 36 | 37 | ### Pattern-based disposal in `await foreach` 38 | 39 | `WithCancellation` and `ConfigureAwait` both return a custom type that does 40 | not implement the interface, just the pattern. `await foreach` does not pick 41 | it up because it does not have pattern-based disposal and the type cannot 42 | implement the `IAsyncDisposable` type because it does not produce a `ValueTask` 43 | return for disposal. 44 | 45 | Proposals: 46 | 47 | 1. Just allow pattern-based disposal for `IAsyncDisposable`. Only allow 48 | pattern-based disposable for `IDisposable` in ref structs. 49 | 50 | a. For `await foreach`, use the pattern, then dynamically check for 51 | interface and use it if present. 52 | 53 | b. For `await foreach`, use the pattern, then statically check for the 54 | interface and use it if present. 55 | 56 | The dynamic check in (1a) is used because in C# 1.0 the non-generic `IEnumerator` 57 | did not implement IDisposable. 58 | 59 | The next question is whether to consider extension methods. The standard pattern 60 | we've previously settled on is: 61 | 62 | 1. Check for pattern 63 | 2. Check for interface 64 | 3. Check for extension methods 65 | 66 | Can we use this pattern for `IAsyncDisposable`? The primary question is whether 67 | to consider extension methods. 68 | 69 | **Conclusion** 70 | 71 | Let's do 1b. We do not have a non-generic `IAsyncEnumerator` that doesn't 72 | implement `IAsyncDisposable`, so the dynamic check is unnecessary. 73 | 74 | We will not consider extension methods for `IAsyncDisposable` or 75 | `IDisposable` (on ref structs). We will consider extension methods for 76 | `IAsyncEnumerable` and `IEnumerable`. 77 | -------------------------------------------------------------------------------- /meetings/2019/LDM-2019-01-23.md: -------------------------------------------------------------------------------- 1 | 2 | # C# Language Design Meeting for Jan 23, 2019 3 | 4 | ## Agenda 5 | 6 | Function pointers ([Updated proposal](https://github.com/dotnet/csharplang/blob/master/proposals/function-pointers.md)) 7 | 8 | ## Discussion 9 | 10 | ### Creation of a function pointer to a managed method 11 | 12 | The proposal is `&Class.Method` to produce a function pointer. The question 13 | is whether `&Class.Method` is target-typed, whether it has a natural type 14 | when there's only one member in the method group, or both. 15 | 16 | Target-typing is useful because, like with delegates, it allows you to select 17 | a unique method out of a method group with multiple incompatible overloads. 18 | 19 | Natural type is useful because it allows things like `var` and `void*`. 20 | 21 | **Conclusion** 22 | 23 | Let's start by only doing target-typing. Also, the section "better function 24 | member" is not necessary without the natural typing. 25 | 26 | ### DllImport CallingConvention? 27 | 28 | There is actually a stub that the compiler calls for P/Invoke with DllImport 29 | that is always done using the managed calling convention, so there's no 30 | reason for function pointers to use the DllImportAttribute. 31 | 32 | NativeCallback is intended for the scenario where you want to avoid the stub 33 | overhead. 34 | 35 | ### NativeCallableAttribute 36 | 37 | Let's look at this in more detail. 38 | 39 | ### Syntax 40 | 41 | ```C# 42 | 1. func* managed int(string) 43 | 2. func*(string)->int 44 | 3. func* managed (string)->int 45 | 4. func* managed (string)=>int 46 | 5. managed int(string)* 47 | 5a. int(string)* 48 | 6. managed int(string) 49 | 7. managed (string)->int 50 | 8. delegate* int(string) 51 | 9. func int(string)* 52 | 10. delegate int(string)* 53 | ``` 54 | 55 | **Conclusion** 56 | 57 | We're not sure about all the potential ambiguities here. Let's look at (5a), 58 | possibly disambiguating with the calling convention. 59 | 60 | ### Things to clarify in spec 61 | 62 | * What does the CLR do if you try to call a method that has a modreq/modopt in 63 | the signature, but the `calli` has the signature without the modreq/modopt? -------------------------------------------------------------------------------- /meetings/2019/LDM-2019-02-25.md: -------------------------------------------------------------------------------- 1 | 2 | # C# Language Design Notes for Feb 25th, 2019 3 | 4 | ## Agenda 5 | 6 | Semantics of `base()` calls in default interface implementations and classes 7 | 8 | ## Discussion 9 | 10 | The exact semantics of `base()` are still unresolved. Consider 11 | the following legacy `base` call. 12 | 13 | ```C# 14 | class A 15 | { 16 | virtual void M() {} 17 | } 18 | 19 | class B : A 20 | { 21 | // override void M() { } 22 | } 23 | 24 | class C : B 25 | { 26 | override void M() => base.M(); 27 | } 28 | ``` 29 | 30 | The behavior for `base` is to find the "nearest" implementation and call 31 | that implementation using a direct call, meaning if B.M is uncommented it 32 | will be called, while if it commented out then A.M will be called. Notably, 33 | if `B` is uncommented at compile time, but at runtime the `B.M` override is 34 | not present *the runtime will call A.M.* This is because the runtime will 35 | continue looking through base classes for a matching signature if the target 36 | method is not present. 37 | 38 | Most importantly, the runtime *does not* yet have this behavior for `base()` 39 | calls in interface implementations. This is because there could be multiple 40 | paths to search down and the current IL encoding does not provide a root 41 | definition to search towards. 42 | 43 | For example, 44 | 45 | ```C# 46 | interface IA 47 | { 48 | void M(); 49 | } 50 | interface IB : IA 51 | { 52 | void IA.M() // If this gets removed, the IC.M call will fail 53 | { 54 | base(IA).M(); 55 | } 56 | } 57 | interface IC : IB 58 | { 59 | void IA.M() => base(IB).M(); 60 | } 61 | ``` 62 | 63 | At the moment, we do not have the time to implement an entire new IL form 64 | for `base()` calls, so we have to implement a behavior in absence of that 65 | feature. 66 | 67 | Choices: 68 | 69 | 1. No `base()` call 70 | 2. `base()` call can only target the original definition of the method 71 | 3. `base(T).M()` call is a direct call to `T` and an error if the method 72 | doesn't exist 73 | 4. `base(T)` starts searching in `T`, but in the compiler looks at the bases 74 | for a unique, most derived implementation. 75 | 76 | For feature evolution, we then have three more choices later. 77 | 78 | 1. Stay as-is 79 | 2. New opcode/behavior for `base()` 80 | 3. New opcode/behavior for `base.` and `base()` 81 | 82 | **Conclusion** 83 | 84 | For the first choice, let's do (3). The emitted code will be a direct call to 85 | that method. It is expected that the runtime will throw an exception if an 86 | implementation is not present in that type. For binding, in classes the 87 | signature used will be the closest override, while for interfaces the 88 | signature will be the member definition. -------------------------------------------------------------------------------- /meetings/2020/LDM-2020-02-03.md: -------------------------------------------------------------------------------- 1 | 2 | # C# LDM for Feb. 3, 2020 3 | 4 | ## Agenda 5 | 6 | Value equality 7 | 8 | ## Discussion 9 | 10 | We split our discussion between two proposals, which end up being very 11 | similar. 12 | 13 | ### 'key' equality proposal 14 | 15 | https://github.com/dotnet/csharplang/pull/3127 16 | 17 | Q: Is comparing `System.Type`s slow? Does it require reflection? 18 | 19 | A: `typeof` does not require reflection and comparing `Type`s is fast. 20 | 21 | Q: Why use a KeyEquals method? 22 | 23 | A: To signify that value equals is used and delegate to the base equality, 24 | when the base opts-in to value equality. By having a well-known signature 25 | in metadata, no special attributes are required for derived types to discover 26 | the pattern. 27 | 28 | Q: Is KeyEquals necessary? Can we use `EqualityContractOrigin` to figure 29 | out that the type implements value equality? 30 | 31 | A: Yes, that seems like it should work. 32 | 33 | *Discussion* 34 | 35 | There's some concern that modifying the public surface area of the type 36 | itself without any type of modifier is too much magic. If we have some 37 | sort of modifier that goes on the type, in addition to the "key" members, 38 | it would be clear that the type implements value equality from the type 39 | declaration, in addition to the member declarations. 40 | 41 | This dovetails into records as a whole in that it would allow the feature sets to be separable. 42 | If a type could have value equality or be a record, the features could be combined to produce a 43 | value record, or the value equality could be left off to allow a record with reference equality. 44 | There's some disagreement on whether this is a positive or a negative. If you view a record as 45 | appropriately having value equality, this is a negative, or vice versa. 46 | 47 | ### 'value' equality proposal 48 | 49 | https://github.com/dotnet/csharplang/issues/3137 50 | 51 | The most visible difference here is that `value` is the name of the modifier, instead of `key`. 52 | This more accurately reflects the term "value equality", but it's unfortunate that we already 53 | have the term "value type" which has a completely different meaning in the language. 54 | 55 | At the moment the proposal also doesn't include the "extra" members, like a strongly 56 | typed Equals, the `==`/`!=` operators, and `IEquatable` interface implementation. 57 | 58 | There's an open question as to whether this feature is preferred for a discriminated 59 | union scenario or not. We have two examples in Roslyn of discriminated unions, our 60 | symbol tree and our bound tree, and they have almost completely different equality 61 | contracts. -------------------------------------------------------------------------------- /meetings/2020/LDM-2020-02-10.md: -------------------------------------------------------------------------------- 1 | 2 | # C# Language Design for Feb. 10, 2020 3 | 4 | # Agenda 5 | 6 | Records 7 | 8 | # Discussion 9 | 10 | We're continuing our attempt to draw out the dependencies and individual features inside records. 11 | 12 | When going through the list, what stands out is: 13 | 14 | - Looking at `with`, we need to figure out what's mentionable in the `with` expression. 15 | 16 | - We need to figure out exactly what we want for how primary constructors fit into records 17 | 18 | There are a number of positives and negatives of primary constructors. On the negative side, 19 | a non-record primary constructor seems to consume syntactic space that could be used for 20 | records. If we think that records are the overwhelmingly common scenario, then it seems like 21 | using the shortest syntax for the most common feature is useful. On the positive side, primary 22 | constructors alone seem to support a simpler way of writing private implementation details. 23 | Separate from the value as a whole, there's some desire to have a special keyword just for 24 | records. That is, even if we didn't do primary constructors, it could be valuable to have 25 | an explicit modifier, like `data` to signify that this type has special behavior. 26 | 27 | One possible pivot is to eliminate some composition syntax entirely, by creating a new type 28 | of declaration, `record`, e.g. 29 | 30 | ```C# 31 | record Point(int X, int Y); 32 | ``` 33 | 34 | This would be equivalent to the syntax that we've been discussing with `data`, namely 35 | 36 | ```C# 37 | data class Point(int X, int Y); 38 | ``` 39 | 40 | but since the `class` keyword is implied by default, the most common scenario would be 41 | just about as short as the shorter `class Point(int X, int Y)` form. 42 | 43 | **Conclusion** 44 | 45 | After taking everything into account, we think having an new keyword for records is good both for 46 | leaving space for non-record primary constructors, and also to serve as a clear signifier of 47 | record semantics. 48 | 49 | -------------------------------------------------------------------------------- /meetings/2020/LDM-2020-02-24.md: -------------------------------------------------------------------------------- 1 | 2 | # C# Language Design for Feb. 24, 2020 3 | 4 | ## Agenda 5 | 6 | 1. Nominal records proposal 7 | 8 | ## Discussion 9 | 10 | ### Nominal records 11 | 12 | https://github.com/dotnet/csharplang/issues/3226 13 | 14 | We've been trying to leave space open for something we're calling "nominal records" where the 15 | concept is that we establish some new system for constructing types based on names, instead of 16 | the order of parameters in a constructor. 17 | 18 | Here we have a refreshed nominal records proposal to examine and consider. 19 | 20 | The proposal says: 21 | 22 | > The main thing you lose out on with nominal construction is a centralized place - the 23 | constructor body - for validation. Property setters can have member-wise validation, but 24 | cross-member holistic validation is not possible. However, for a feature such as records that is 25 | for data not behaviors, that seems to be a particularly small sacrifice. 26 | 27 | We don't necessarily agree that this is a small restriction, and there may be some way to add 28 | support for it. 29 | 30 | When it comes to the `With` we do need to decide what members are copied over in non-destructive 31 | mutation. One strategy is to use the "surface area" of the object, which is defined as the 32 | constructor parameters, along with the public fields and properties that have some sort of 33 | "setter". 34 | 35 | Alternatively, we could copy over the state of the object. This would be equivalent to the use 36 | of the `MemberwiseClone` approach as we discussed in previous design meetings. 37 | 38 | **Conclusion** 39 | 40 | There are many details to work out, but there's consensus that we want to investigate adding 41 | nominal records in the future. 42 | -------------------------------------------------------------------------------- /meetings/2020/LDM-2020-06-10.md: -------------------------------------------------------------------------------- 1 | 2 | # C# LDM for June 10, 2020 3 | 4 | ## Agenda 5 | 6 | 1. "Roles" 7 | 8 | ## Discussion 9 | 10 | Exploration of previous proposal: #1711 11 | 12 | This is a topic that we've explored before which we're reviving for further consideration and discussion. 13 | 14 | We have a "role" proposal, but it's more of a starting point for a final design. There are a number of 15 | different problems we can presumably solve here, but it seems like we have some intersecting features that 16 | might address multiple problems simultaneously. 17 | 18 | There are many tradeoffs to consider in these designs. One of the most well-known is sometimes called 19 | "incoherence," where the ability to implement an interface in two ways on the same type effectively causes 20 | the two implementations to "cross" each other in ways that can be hard to predict. For instance, if two 21 | people implemented `IEquatable` on the same third-party type, and both added it to a dictionary, if they 22 | used different `GetHashCode` implementations then the same member could be added twice, and each consumer 23 | wouldn't see the implementation used by other consumers. 24 | 25 | Another tradeoff is the ability to use the role as a type, namely refer to it in a type position. This 26 | is often desirable, but has some tradeoffs in type equivalence (see SML modules for alternative notions 27 | of type equivalence through functors). 28 | 29 | The Roles proposal as a whole seems very powerful, but there are many big questions here. The biggest, 30 | most pressing question is: what problems do we think are the most important and how big a feature do 31 | we need to address them? Providing a way to abstract over different numeric abstractions is a concrete 32 | scenario, but it may not need the fully generalized mechanism. Allowing existing types to conform 33 | to an abstract after definition is also powerful and has many possible use cases, but how flexible 34 | do we need to make that mechanism? Can it only be used in generics? Can you implement abstractions 35 | defined in other compilations on types defined in other compilations? 36 | 37 | The performance concerns are also very real. We have a few mechanisms for abstraction in the language 38 | today, but a lot of those mechanisms come with performance costs like allocation that make them 39 | unusable in performance-sensitive scenarios. We would like more zero-cost abstractions if possible, 40 | but we're not sure what functionality we could provide in those circumstances and whether the features 41 | would fit well into the existing ecosystem. -------------------------------------------------------------------------------- /meetings/2020/LDM-2020-12-07.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for December 7th, 2020 2 | 3 | ## Agenda 4 | 5 | 1. [Required Properties](#required-properties) 6 | 7 | ## Quote(s) of the Day 8 | 9 | - "I also can't see anyone's video, so raise your hand [in Teams] if you're not here." 10 | - "If you can't solve required properties, you're not making a time machine." 11 | 12 | ## Discussion 13 | 14 | ### Required Properties 15 | 16 | https://github.com/dotnet/csharplang/discussions/4209 17 | 18 | Today, we took a look at the next revision of the required properties proposal, after a few months of design work from a smaller 19 | team to flesh out the design. We had a small questions coming out of the meeting: 20 | 21 | * Could assignments in the nominal parameter list always imply `base.`? It would make it easier for automatically considering 22 | hidden properties being initialized. 23 | * We could make it more user friendly by possibly adding warning when a property that is required by the constructor is definitely 24 | assigned in the constructor? 25 | * There's still some debate as to this should only be a source-breaking change. 26 | * Is `init` the right word? Maybe `requires` would be better? 27 | 28 | More generally, the reaction to this in the LDM was mixed. While we believe that this is the best proposal we've seen to date, it's 29 | very complicated and introduces a bunch of new concepts. We may need to start looking at simplifying scenarios and seeing whether that 30 | allows us to cut this proposal down a bit. 31 | -------------------------------------------------------------------------------- /meetings/2020/Required_Properties_2020_09_16.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/meetings/2020/Required_Properties_2020_09_16.pdf -------------------------------------------------------------------------------- /meetings/2020/delectable_tea_2020_07_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/meetings/2020/delectable_tea_2020_07_27.png -------------------------------------------------------------------------------- /meetings/2021/LDM-2021-01-05.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for Jan. 5th, 2021 2 | 3 | ## Agenda 4 | 5 | 1. [File-scoped namespaces](#file-scoped-namespaces) 6 | 7 | ## Quote of the Day: 8 | 9 | - "I see a big tropical void where [redacted's] face was... It's so annoying" 10 | - "It's so cold here, it's 70 [F]" 11 | 12 | ## Discussion 13 | 14 | ### File-scoped namespaces 15 | 16 | https://github.com/dotnet/csharplang/issues/137 17 | 18 | Today, we looked at some of the details around this feature, specifically what should be supported before or after a top-level 19 | namespace declaration. The proposal as written allows only extern aliases, using directives, and global attributes. The proposal 20 | also does not allow multiple top-level namespaces: you can only have one in the file, and all following type declarations are 21 | considered to be part of that namespace. The debate, therefore, centers on whether we allow multiple of these declarations in a 22 | file, what they would mean in that case, and whether we allow a top-level namespace at the same file as top-level statements. 23 | 24 | In many ways, this seems like a style question. Syntactically, regardless of whether allow these concepts to be mixed/duplicated 25 | in a single file in the formal grammar, the compiler will have to implement rules for what this means in order to provide a good 26 | IDE experience. There is potential value is allowing this to be flexible, as we generally do not take strong stances on syntax 27 | formatting guidelines beyond the default rules shipped with Roslyn, and those are very customizable to allow users to decide 28 | whether to allow them or not (`var` vs explicit type has 3 major doctrines, for example). By allowing all forms here, we would 29 | let users decide what is preferred to them and what is not. 30 | 31 | That being said, however, we have concerns that we even understand what code like this would do: 32 | ```cs 33 | namespace X; 34 | class A {} 35 | namespace Y; 36 | class B {} 37 | ``` 38 | For this scenario, some people would expect these types to be `X.A` and `Y.B`, while others would expect them to be `X.A` and 39 | `X.Y.B`. We have additional concerns around how this type of code would read in the presence of top-level statements, and 40 | whether there would be enough visual contrast between the end of the top-level statements, the namespace, and then types under 41 | the namespace, or whether that would be confusing to read. If we restrict the usage now, nothing would stop us from loosening 42 | restrictions in a later language version if we discover that we were too restrictive initially, but if we let the genie out of 43 | the bottle now, we can never put it back in. 44 | 45 | #### Conclusion 46 | 47 | No conclusion today. We're largely split between these two extremes, allowing everything or allowing nothing. We'll take this 48 | back up again soon to finish debate and settle on a conclusion. 49 | -------------------------------------------------------------------------------- /meetings/2021/LDM-2021-02-24.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for Feb 24th, 2021 2 | 3 | ## Agenda 4 | 5 | 1. [Static abstract members in interfaces](#static-abstract-members-in-interfaces) 6 | 7 | ## Quote of the Day 8 | 9 | - "I'm not using the monoid word, I'm trying to make it relatable" 10 | 11 | ## Discussion 12 | 13 | ### Static abstract members in interfaces 14 | 15 | https://github.com/dotnet/csharplang/issues/4436 16 | 17 | Today we went over the proposed specification for `static` abstract members. In order to scope the initial implementation, this proposal 18 | intentionally limits such members to _only_ `abstract` members, not `virtual` members. This is due to complexity in passing along the 19 | "instance" that the static is operating on. Consider this example: 20 | 21 | ```cs 22 | interface I 23 | { 24 | virtual static void I1() { I2(); } 25 | abstract static I2(); 26 | } 27 | 28 | class C : I 29 | { 30 | public static void I2() {} 31 | } 32 | 33 | C.I1(); 34 | // How does the runtime pass along the information that the type here is C, 35 | // and I.M1() should invoke C.I2()? 36 | ``` 37 | 38 | Given the complexity of implementation of this scenario and the lack of current motivating examples, we will push this out for a later 39 | version unless our investigations of representing generic math end up needing it. 40 | 41 | #### `==` and `!=` operators 42 | 43 | These are restricted in interfaces today because interface types cannot implement `object.Equals(object other)` and `object.GetHashcode()`, 44 | which are integral to implementing the operators correctly. We can lift that restriction for `abstract static` members, as the implementing 45 | concrete type will then be required to provide implementations of `Equals(object other)` and `GetHashcode()`. 46 | 47 | #### `sealed` on non-abstract members 48 | 49 | We don't have any strong feelings on allowing `sealed` on non-virtual `static` interface members. It's fine to include in the proposal. 50 | 51 | #### Conversion restrictions 52 | 53 | As we implement a set of math interfaces, we'll come across parts of the current restrictions that make it impossible. We should be cautious 54 | here and only lift restrictions as much as is necessary to implement the target scenarios. We can review the rules in depth when they have 55 | been proven out by final usage. 56 | -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-01-05-OHIMark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/meetings/2022/LDM-2022-01-05-OHIMark.jpg -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-06-29.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for June 29th, 2022 2 | 3 | ## Agenda 4 | 5 | - [UTF-8 literal concatenation operator](#utf-8-literal-concatenation-operator) 6 | 7 | ## Quote of the Day 8 | 9 | - "This is an example of our admirable quality that no stone is left unturned" 10 | 11 | ## Discussion 12 | 13 | ### UTF-8 literal concatenation operator 14 | 15 | https://github.com/dotnet/csharplang/issues/184 16 | https://github.com/dotnet/csharplang/pull/6221 17 | 18 | Today, we looked at a small proposal update for UTF-8 strings, based on BCL dogfooding feedback: the ability to concatenate UTF-8 string literals 19 | together with the `+` operator so that long strings can be split across lines. This is similar to the work with interpolated string handlers, where 20 | we similarly enabled the `+` operator for splitting strings across lines. We had two main discussion points: 21 | 22 | First, should we enable `+` as a general operator on all `ReadOnlySpan`s? For example, should the following code work? 23 | 24 | ```cs 25 | ReadOnlySpan M() => "hello "u8; 26 | var helloWorld = M() + "world"u8; 27 | ``` 28 | 29 | We don't think that is a general case we want to support: concatenation of literals can be done easily at compile time, but this would need a general 30 | ability to add `ReadOnlySpan`s together, and we don't know how that would work. Where would the resulting byte sequence live, for example, and 31 | what would be its lifetime? 32 | 33 | Second, we thought about whether this operator should have precedence over a user-defined operator `+` on `ReadOnlySpan`? According to the C# spec, 34 | all existing predefined operators in C# _do not_ have precedence over user-defined operators. However, this is not how the compiler is actually 35 | implemented: the native C# compiler had a bug that always used predefined operators, even when the underlying type defined a `+` operator itself, and 36 | Roslyn reimplemented that bug during its creation. When implementing the `+` predefined operator for `ReadOnlySpan`, however, we did not 37 | carry that bug forward, so if a user defines their own `ReadOnlySpan` with a `+(ReadOnlySpan left, ReadOnlySpan right)` operator defined on 38 | it, that operator will be preferred over this predefined one. We could go and reimplement the bug for this case as well, but we don't think the 39 | scenario is important enough to spend the time, and it will simplify the spec if we continue to specify predefined operators exactly as they are today, 40 | rather than carving out a special case for this `+` operator. 41 | 42 | #### Conclusion 43 | 44 | Proposal accepted. 45 | -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-07-13.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for July 13th, 2022 2 | 3 | ## Agenda 4 | 5 | 1. [Lambda default parameters](#lambda-default-parameters) 6 | 7 | ## Quote of the Day 8 | 9 | - "We love to point out failures, it's what we do" 10 | 11 | ## Discussion 12 | 13 | ### Lambda default parameters 14 | 15 | https://github.com/dotnet/csharplang/pull/6274 16 | https://github.com/dotnet/csharplang/issues/6051 17 | 18 | Today, we reviewed the draft specification for default lambda parameters. There are two main parts of this proposal we need to consider: 19 | 20 | 1. The actual changes to lambdas themselves. These are relatively straightforward, with only a few nuanced sections we need to consider. 21 | 2. Changing the natural type of method groups. This is more nuanced, as it will be a breaking change from C# 10. 22 | 23 | For the first point, we had relatively few pieces of feedback. We think that we should indeed error when the default parameter value of an argument 24 | differs from the target type. For example, this should be an error: 25 | 26 | ```cs 27 | delegate void D(int i = 0); 28 | D d = (int i = 1) => {}; // Error: default parameter values differ. 29 | ``` 30 | 31 | The one case that we think should be acceptable is when the lambda does not specify a default parameter value at all. This is an important backcompat 32 | case as it as worked since lambdas were introduced, as well as being user convenience. 33 | 34 | ```cs 35 | delegate void D(int i = 0); 36 | D d1 = i => {}; // Fine: no value specified 37 | D d2 = (int i) => {}; // Fine: no value specified 38 | ``` 39 | 40 | For the second part, we think we need a more detailed understanding of where the breaks can occur before we decide for sure that we will accept the 41 | break. We know from C# 10 how subtle and painful breaks here can be. While they would be more limited in scope, and we think that it would only breaks 42 | since C# 10, not since lambdas were introduced, we want to understand the space more before committing. 43 | 44 | Finally, we briefly considered whether we should support `params` parameters as well. We think they're interesting, but didn't make a final decision today. 45 | 46 | #### Conclusion 47 | 48 | The lambda rules themselves are accepted, with the error exception for lambdas that don't specify default parameters being converted to a type that does 49 | have them. We will get a better understanding on method groups before making a decision. 50 | -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-07-27.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for July 27th, 2022 2 | 3 | ## Agenda 4 | 5 | 1. [`scoped` for local declarations](#scoped-for-local-declarations) 6 | 7 | ## Quote of the Day 8 | 9 | - *nervous chuckling* "That's actually an interesting question!" "I know, it's just when you say scary things." 10 | 11 | ## Discussion 12 | 13 | ### `scoped` for local declarations 14 | 15 | https://github.com/dotnet/roslyn/issues/62039 16 | https://github.com/dotnet/csharplang/issues/1147 17 | 18 | Today, we looked at allowing `scoped` as a local modifier in all local declaration context, such as `using`s, `foreach` iterator variables, and such. We like the idea in principle: users don't 19 | think of the various different grammatical ways of creating a local variable differently, they think of them all as locals. There were a couple more in-depth points of discussion about the 20 | implementation: 21 | 22 | * Is `scoped` or not something that `var` should be able to infer? This matters for deconstruction, as in `var (x, y) = MethodCall();`. After some consideration, we don't think scopedness is 23 | something we can or should infer. It might also vary between each of the deconstruction variables. Given this, we think that `scoped` needs to explicitly declared, not inferred in any local case. 24 | * The specification for `scoped` doesn't particularly line up with how we consider modifiers. We'd like to think of this as a new kind of modifier, a modifier that must go directly on a type, rather 25 | than a modifier that can go anywhere in the modifiers list of a method. Unlike method modifiers, `scoped` is specifically a modifier on either the return value or a parameter value, and should be 26 | applied in those locations. `scoped unsafe Span M() => ...;`, for example, isn't legal. The `scoped` affects the return, while the `unsafe` generally affects the method body. We therefore think 27 | that the specification (and Roslyn implementation) should match this intuition. 28 | 29 | #### Conclusion 30 | 31 | We approve the general concept in this issue, but the grammar specification needs to be updated. 32 | -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-08-03.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for August 3rd, 2022 2 | 3 | ## Agenda 4 | 5 | 1. [`ref` fields specification updates](#ref-fields-specification-updates) 6 | 7 | ## Quote of the Day 8 | 9 | - "If anyone is confused by these rules, you can hit me up anytime. I advise caffeine before the meeting." 10 | 11 | ## Discussion 12 | 13 | ### `ref` fields specification updates 14 | 15 | https://github.com/dotnet/csharplang/issues/6337 16 | 17 | Today, we looked at changes that have been made to the `ref` fields feature from implementation feedback. Changes 1 and 2 were approved with very little discussion. Point 3 generated much more 18 | discussion. 19 | 20 | In particular, we discussed the change that `` `this` for `struct` instance methods `` is now implicitly `scoped`. Part of this overlaps with the next point, that `` `ref` parameters that refer to `ref struct` types `` 21 | should be `scoped` by default, but it goes further, making it the default for all structs, `ref` or not. The general question is: should we narrow this to just `ref struct` types? This would be a breaking change, and 22 | we've accepted a breaking change in this feature already with the updated escape rules under the principle of reducing confusion and having the language do the right thing. This case is less clear-cut though: for the 23 | escape rules, the general consensus is that the old defaults were wrong for nearly all methods, and real-world data indicated that very, very few such methods existed. That isn't the case for the `this` parameter on 24 | `struct` methods though: `ImmutableArray.ItemRef(int index)`, for example, would be broken by having `this` be implicitly unscoped. If we were designing the system from scratch, we might have narrowed this rule, 25 | but given that the compat concerns are larger and the benefit isn't clear cut, we don't think we should narrow this rule. 26 | 27 | We also took a bit of time to think about whether we were cutting off our ability to make future innovations in the space of `ref struct`s with these rules, such as allowing them in generics, implementing interfaces, 28 | and future flow analysis improvements. We don't think that we're introducing any new problems in those spaces, so we'll proceed as is. 29 | 30 | We did not get to points 4 and 5 today. We will discuss those over email and potentially in a future in-person LDM, if required. 31 | 32 | #### Conclusion 33 | 34 | Points 1-3 are approved. 35 | -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-08-10.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for August 10th, 2022 2 | 3 | ## Agenda 4 | 5 | 1. [`required` property default nullability](#required-property-default-nullability) 6 | 7 | ## Quote of the Day 8 | 9 | - "If I'm going on a long journey I always think I can get all this stuff done on the plane. I always end up watching a movie." 10 | 11 | ## Discussion 12 | 13 | ### `required` property default nullability 14 | 15 | https://github.com/dotnet/csharplang/issues/6359 16 | 17 | Today we looked at what the default state of required properties should be at the beginning of a constructor. As implemented and specified currently, properties 18 | will be treated as if they have the null state they claim, so `public required string Prop { get; set; }` would have a not-null state at the start of a constructor. 19 | We don't think this is a good idea: in C# 10, users could either count on a chained constructor having set all members, or will have the default state of all members 20 | set to not-null. We think `required` serves as a good heuristic indicator that the property should be set to `default(T)` at the start of the constructor. The exception 21 | to this is when the user chains to a constructor has specified `SetsRequiredMembers` on the constructor. 22 | 23 | #### Conclusion 24 | 25 | We accept the following rules: 26 | 27 | 1. When chaining to a constructor that does not have `SetsRequiredMembersAttribute`, all `required` members have a null state of `default(T)`, including those 28 | required members from a base type. 29 | 3. At the end of a constructor that is attributed with `SetsRequiredMembersAttribute`, all `required` members must have the null state they are declared with, 30 | including those required members from a base type. 31 | -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-10-26.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for October 26th, 2022 2 | 3 | ## Agenda 4 | 5 | - [Null-conditional assignment](#null-conditional-assignment) 6 | 7 | ## Quote of the Day 8 | 9 | - "Can you see this word I've highlighted?" "3..., 4..., 5..., 6..., 7..., 8..., 9..., 10..., 11..., 12..., 13..., 14..., 15! 15 second delay in the video" 10 | 11 | ## Discussion 12 | 13 | ### Null-conditional assignment 14 | 15 | https://github.com/dotnet/csharplang/issues/6045 16 | 17 | Today we took a complete look at the proposal for null-conditional assignment. Overall, there were two points of concern with the feature: 18 | 19 | 1. Is the intuition around what `a?.b = c();` actually does at runtime good? Most of the LDT was in agreement what the semantics of this would be without 20 | discussion, which is a good sign. However, a few members did say that their first read was that `c()` would be executed regardless of whether `a` was null. 21 | We think this is very similar to the reaction to `?.` in C#, where many found the behavior intuitive, but a few users had to learn. We're therefore ok with 22 | the intuition of the behavior of this feature. 23 | 2. We took a look at nested scenarios, such as `a?.b = c?.d = e?.f;`, and thought about whether the semantics would be confusing. There are a few possible 24 | results from this nested assignment: 25 | 1. If `a` is `null`, nothing else will be evaluated. 26 | 2. If `a` is non-`null` and `c` is `null`, `a.b` will be assigned `null` and `e?.f` will not be evaluated. 27 | 3. If `a` and `c` are non-`null`, `e?.f` will be evaluated and the result will be assigned to `c.d` and `a.b`. 28 | 29 | While we think this syntax form is probably not a good one, and we won't encourage users to use it, we think that it's a natural consequence of the way our 30 | grammar works, and don't see any good reason to forbid it. 31 | 32 | #### Conclusion 33 | 34 | The design is approved as is. 35 | -------------------------------------------------------------------------------- /meetings/2022/LDM-2022-12-14.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for December 14th, 2022 2 | 3 | ## Agenda 4 | 5 | - [Breaking change for raw string literals](#breaking-change-for-raw-string-literals) 6 | - [Program as internal by default](#program-as-internal-by-default) 7 | 8 | ## Quote of the Day 9 | 10 | - "Give everyone the ability to quickly filibuster it" 11 | 12 | ## Discussion 13 | 14 | ### Breaking change for raw string literals 15 | 16 | https://github.com/dotnet/roslyn/pull/65973 17 | 18 | An email discussion approved this change. No significant concerns were raised in LDM or on email. 19 | 20 | ### Program as internal by default 21 | 22 | https://github.com/dotnet/csharplang/issues/6769 23 | 24 | Today we revisited the defaults for top-level statements, looking at scenarios that are impacted by our [original decision](../2021/LDM-2021-07-12.md#speakable-names-for-top-level-statements). 25 | Some friction has been encountered because of this, particularly in scenarios around testing, and we are generally interested in addressing the scenario in some fashion. There is, however, some 26 | debate on the best way to address these scenarios; language changes are big hammers, and we intentionally left knobs in the language (other partial declarations) to address concerns with the 27 | default accessibility of the `Program` type. There are visceral reactions to the statement "Make this API public for testing", as program authors generally want to be intentional with their 28 | public surface area. This is true for executables too, as executables can be referenced by other programs. Given this, we will take the proposal back for more design, and perhaps find a 29 | solution in tooling for the problem, rather than changing the language here. 30 | 31 | #### Conclusion 32 | 33 | Proposal will be revisited after more design work (which may decide on a non-language solution to the problem). 34 | -------------------------------------------------------------------------------- /meetings/2023/LDM-2023-01-09.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for January 9th, 2023 2 | 3 | ## Agenda 4 | 5 | - [Working group re-evaluation](#working-group-re-evaluation) 6 | 7 | ## Quote of the Day 8 | 9 | - "Different variations of crazy come together to make a whole sane person." 10 | 11 | ## Discussion 12 | 13 | ### Working group re-evaluation 14 | 15 | We've had a few months with working groups, and think now is a good time to do a small retrospective on whether the strategy is working well for us. 16 | One concern that we have is that team members are feeling overloaded on working groups. Several members felt a good amount of FOMO (fear of missing 17 | out) during the sign up process, expecting that all the interesting discussions would occur in the working group, rather than at the LDM. This has lead 18 | to the working groups not actually being able to get anything done and taking up more development time that was intended. Some of the working groups 19 | have also met a bit too often, when there wasn't enough driving interest. Working groups are creative effort, and trying to force creative effort when 20 | there isn't enough enthusiasm doesn't accomplish anything. We've settled on some changes in our process to help the groups be more nimble: 21 | 22 | 1. Reduce group memberships. While we're not putting constraints on minimum or maximum memberships, LDT members should aim to reduce their workload 23 | with the number of groups they join. Group membership should not be a passive topic where you just listen in: it should be an active participant 24 | effort. 25 | 2. Working groups should bring their progress to the full LDM more often. A significant driver of the over-subscription was FOMO, but the working groups 26 | weren't intended to replace the full LDM discussions on topics. Proposals will still be debated in full with the full LDM, and more frequent check-ins 27 | will help make sure that the proposals are still a product of the entire group. While the working group can delve into spaces and form opinions, 28 | authority is still with the LDM for the final shape of proposals. 29 | 3. Reduce meeting frequency. Most groups went out and scheduled recurring meetings every week. This was too often for most groups, and resulted in 30 | overburdening the group leaders who needed to establish topics and record notes. Teams should meet as often as makes sense for the team: if there's 31 | been no progress on an idea, we shouldn't try to force the creative process. As part of this, some groups may stop meeting altogether, and that's ok. 32 | 33 | We hope this set of changes will enable the working groups to be more effective, and make sure that LDT members have enough time to contribute to working 34 | groups while continuing to work on their regular teams. 35 | -------------------------------------------------------------------------------- /meetings/2023/LDM-2023-03-01.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for March 1st, 2023 2 | 3 | ## Agenda 4 | 5 | - [Discriminated Unions Summary](#discriminated-unions-summary) 6 | 7 | ## Quote of the Day 8 | 9 | - "We're seconds from lattice theory references" 10 | 11 | ## Discussion 12 | 13 | ### Discriminated Unions Summary 14 | 15 | https://github.com/dotnet/csharplang/discussions/7010 16 | 17 | Today, the working group took a summary of their discussions back to LDM and went over them with the group. 18 | This took the entire session, and only clarifying questions were asked; the LDM will discuss thoughts on the 19 | proposal next week, after members have had some time to think about the topics presented today. 20 | -------------------------------------------------------------------------------- /meetings/2023/LDM-2023-05-17.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for May 17th, 2023 2 | 3 | ## Agenda 4 | 5 | - [Inline arrays](#inline-arrays) 6 | 7 | ## Quote of the Day 8 | 9 | - "A strategy to hold ourselves hostage" 10 | 11 | ## Discussion 12 | 13 | ### Inline arrays 14 | 15 | https://github.com/dotnet/csharplang/issues/1314 16 | https://github.com/dotnet/csharplang/blob/7b5d0bbcd552e0541db4a5afdad3b75210037120/proposals/inline-arrays.md#the-foreach-statement 17 | 18 | Following up from a [previous discussion](LDM-2023-05-01.md#fixed-size-buffers) on inline arrays, we looked at `foreach` support for inline 19 | array types. The current implementation plan for `foreach` on these types is to do it via `Span` or `ReadOnlySpan`; as these are 20 | `ref struct` types, they cannot be `foreach`ed in an `async` method. This restriction makes sense for inline arrays sometimes, as they are 21 | more likely to be passed around via `ref` than standard types. Refs can't live past an `await` boundary, so this makes sense for such 22 | variables. However, it doesn't make as much sense for inline arrays that are local by value: for example, a local of an inline array type 23 | would not be foreachable in an `async` method as proposed today. There are two possible improvements we could make here: 24 | 25 | 1. Be more granular with `ref struct` usage in `async` methods. As long as the `ref struct` does not cross an `async` boundary, it should be safe 26 | to reference. If we were smarter about `ref struct` usage in `async` methods, then inline arrays would simply come along for the ride. It's 27 | not a perfect solution though, as there would still be errors for inline array values that can be safely lifted to a display class when a 28 | `foreach` loop `await`ed in its body. 29 | 2. Have special lowering for inline arrays for async methods. `ref`s to inline arrays would continue to be blocked in `async` methods, as today, 30 | inline array values (mainly locals and parameters) can be safely lifted to a display class and iterated over across `await` boundaries 31 | without any issues around observability of changes. 32 | 33 | These solutions are not mutually exclusive; we can do either one, both, or none. What we are fairly certain of at this point, though, is that 34 | it is unlikely that we can fit either solution into C# 12. After some discussion, we decided that we are fine with shipping an initial version 35 | of inline arrays that restricts `foreach` in `async` methods, and later loosen restrictions on it as we can. 36 | 37 | #### Conclusion 38 | 39 | We will support `foreach` over inline arrays, even if it starts as restricted in `async` methods. We will encourage alternate lowering strategies 40 | and smarter `ref` rules in async methods where we can, but that will be a longer-term effort. 41 | -------------------------------------------------------------------------------- /meetings/2023/LDM-2023-08-07.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for August 7, 2023 2 | 3 | ## Agenda 4 | 5 | - [Improvements to method group natural types](#improvements-to-method-group-natural-types) 6 | 7 | ## Quote of the Day 8 | 9 | - "I've never said I'm not a hypocrite" 10 | 11 | ## Discussion 12 | 13 | ### Improvements to method group natural types 14 | 15 | https://github.com/dotnet/roslyn/issues/69222 16 | 17 | The proposal is a possible improvement over the mechanism decided on [July 24th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-07-24.md#method-group-natural-types-with-extension-members), where the uniqueness of a method group that allows it to have a natural type is determined scope by scope rather than across all possible instance and extension methods. 18 | 19 | In that proposal, an instance or extension method can still be considered to apply, even if it would later be rejected by subsequent checks. For instance, type arguments might not satisfy constraints: 20 | 21 | ``` c# 22 | var x = new C().M; // CS8917 The delegate type could not be inferred. 23 | 24 | public class C 25 | { 26 | public void M() { } 27 | public void M(object o) where T : class { } 28 | } 29 | ``` 30 | 31 | The proposal is to move these checks earlier, removing failing candidates so another candidate can be unique. 32 | 33 | This additional pruning would cause us to depend on more details: It would succeed in more scenarios but at the cost of being more vulnerable to changes in those details. However, we accepted those same tradeoffs in method invocation scenarios several versions ago during a round of overload resolution improvements. This seems equivalent. 34 | 35 | The proposal would incur slight breaking changes. They seem fairly negligible, but we should give it time in preview to confirm that we are not missing scenarios. 36 | 37 | #### Conclusion 38 | 39 | Change is approved. It will not be in C# 12, as we need bake time in preview to confirm that breaks are acceptable. 40 | -------------------------------------------------------------------------------- /meetings/2023/LDM-2023-10-04 Intro to Trimming and AOT.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/meetings/2023/LDM-2023-10-04 Intro to Trimming and AOT.pdf -------------------------------------------------------------------------------- /meetings/2023/LDM-2023-12-11.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for December 11th, 2023 2 | 3 | ## Agenda 4 | 5 | - [Extensions](#extensions) 6 | 7 | ## Quote(s) of the Day 8 | 9 | - "Welcome to the last regular LDM of the year." "You missed the chance to do last explicit meeting." *Sigh* "No, **you** could have done that" "I wanted you to pick it up implicitly." 10 | "If you keep making bad jokes we may have to extend the meeting." 11 | 12 | ## Discussion 13 | 14 | ### Extensions 15 | 16 | https://github.com/dotnet/csharplang/issues/5497 17 | https://github.com/dotnet/csharplang/issues/7771 18 | 19 | Now that we're entering the next cycle of C# design, we're bringing back issues that have been on the backburner while we focused on C# 12. First on the docket is extensions; we started 20 | LDM with a quick recap on the general proposal, then dove straight into looking at the progress on lowering that has been made in the past few months. This design has evolved a great deal 21 | since we initially looked at it, and has undergone multiple iterations as we discuss with runtime architects on what is feasible and what is not. Rather than restating the lowering document, 22 | these notes will just point out some comments that we had while going over it. 23 | 24 | * We're unsure about the Punnett Square of extension inheritance, in particular whether implicit->implicit inheritance is actually necessary. The only question is whether we'll need that 25 | for multiple implicit interface implementation; if there are multiple implicit extensions that implement different interfaces on a type, and then that type is used in a locaton that 26 | constrains to both of those interfaces, will we need to synthesize a new implicit extension that inherits from each original extension to combine them? Will the user need to manually 27 | introduce that extension? 28 | * We continue to have no good ideas on how to solve nested generics in the general case that can also handle extensions that add interfaces. The representation we've chosen currently 29 | is representation-preserving at the top level, but `List` cannot be easily converted to `List` without an allocation somewhere. 30 | * We could consider erasure here, but that will only postpone the problem, as extensions can add interfaces (eventually). 31 | * Interface member lookup through extensions will be tricky. If the runtime definition of an interface adds a member, and the underlying type has a method that would normally be automatically 32 | hooked up to that member at runtime, what will do that for an extension implementation and its underlying type? 33 | * May need some runtime help for this one. 34 | 35 | Ultimately, there are no conclusions today. We'll keep iterating on these questions and bring lowering back to LDM for continued discussion in future sessions. 36 | -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-03-27-presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/meetings/2024/LDM-2024-03-27-presentation.pdf -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-03-27.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for March 28th, 2024 2 | 3 | ## Agenda 4 | 5 | - [Discriminated Unions](#discriminated-unions) 6 | 7 | ## Quote of the Day 8 | 9 | - "I think [redacted LDT member] is a decent person... oh wait, did you turn the mic back on?" 10 | - `public sealed enum Planets { Earth, Jupiter, Mars, Mercury, Neptune, Pluto, Saturn, Uranus, Venus }` 11 | 12 | ## Discussion 13 | 14 | ### Discriminated Unions 15 | 16 | https://github.com/dotnet/csharplang/issues/113 17 | 18 | Today, we took a look at the areas the discriminated unions working group has been investigating. A significant portion of the meeting was going over slides, 19 | which have been included [here](./LDM-2024-03-27-presentation.pdf). These slides have been helpfully annotated with speaking notes, so this set of notes won't 20 | go deep into the points covered in the presentation itself. 21 | 22 | We had a few reads of the room during the meeting, particularly at the end, to try and help focus on the next direction for the working group to move. One clear 23 | result from these reads was that we need to support existing "closed" type hierarchies in some fashion, even if it's just in exhaustiveness in pattern matching. 24 | This already has a [championed issue](https://github.com/dotnet/csharplang/issues/485), and we don't think that we necessarily need to tie it to DUs specifically, 25 | but that we should understand how the broader DU feature will behave so that we can integrate these existing hierarchies into that feature set, rather than having 26 | multiple sets of behaviors depending on how such a hierarchy was defined. 27 | We were also unable to clearly come to a decision around implementation strategies after this meeting; we have a much better understanding now of the tradeoffs 28 | that various strategies will have, both from a performance perspective, and from a versioning perspective, but we still need to narrow the scenarios we're trying 29 | to address further before we can determine what weights to put on those tradeoffs. 30 | -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-04-01-presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/meetings/2024/LDM-2024-04-01-presentation.pdf -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-07-24.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for July 24th, 2024 2 | 3 | ## Agenda 4 | 5 | - [Discriminated Unions](#discriminated-unions) 6 | - [Better conversion from collection expression with `ReadOnlySpan` overloads](#better-conversion-from-collection-expression-with-readonlyspant-overloads) 7 | 8 | ## Quote of the Day 9 | 10 | - "I put that there so people will complain" 11 | 12 | ## Discussion 13 | 14 | ### Discriminated Unions 15 | 16 | Champion issue: https://github.com/dotnet/csharplang/issues/113 17 | Proposal: https://github.com/dotnet/csharplang/blob/18a527bcc1f0bdaf542d8b9a189c50068615b439/proposals/TypeUnions.md 18 | 19 | First up today, the discriminated unions working group presented the proposal they've been working on for a while to the broader LDM. This was a broad overview session, rather than a deep dive into nitty-gritty 20 | questions; there are still plenty of little details that will need to be filled in, but we're cautiously optimistic about this proposal and moving forward with it. There was some concern about some of the 21 | ternary behavior, but we can dig more into that as we bring this proposal back for detailed follow ups in the future. 22 | 23 | ### Better conversion from collection expression with `ReadOnlySpan` overloads 24 | 25 | Champion issue: https://github.com/dotnet/csharplang/issues/8297 26 | Related issue: https://github.com/dotnet/roslyn/issues/73857 27 | 28 | We followed up from [last Wednesday](LDM-2024-07-17.md#better-conversion-from-collection-expression-with-readonlyspant-overloads), revisiting an even narrower proposal; just looking at implicit reference 29 | conversions, rather than all implicit conversions except numeric conversions. However, LDM still does not prefer the narrow fix; it has edge cases and isn't generalizable. There is some concern that rules around 30 | `OverloadResolutionPriority` might not work here; `string.Concat` has 15 overloads in .NET 9, and this isn't the type of break-glass scenario `OverloadResolutionPriority` was designed for. Given this, we reaffirm 31 | that we want to look into doing the recursive approach, ie better conversion from element. 32 | 33 | #### Conclusion 34 | 35 | Continue looking into option 3, better conversion from element. 36 | -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-10-28.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for October 28th, 2024 2 | 3 | ## Agenda 4 | 5 | - [Increment and Decrement Operators in null conditional access](#increment-and-decrement-operators-in-null-conditional-access) 6 | - [`yield` in `try` / `catch`](#yield-in-try--catch) 7 | 8 | ## Discussion 9 | 10 | ### Increment and Decrement Operators in null conditional access 11 | 12 | Champion issue: https://github.com/dotnet/csharplang/issues/6045 13 | Spec: https://github.com/dotnet/csharplang/blob/28d016c4d9fc8cbbedfeb75c539e6bebbedc4292/proposals/null-conditional-assignment.md#incrementdecrement-operators 14 | 15 | An issue came up during implementation of null conditional access, which allows null conditionals as the target of an assignment. 16 | 17 | The question is whether to allow prefix/postfix increment/decrement operators, and the proposal is not to allow them. The alternative when increment or decrement is needed is to use compound assignments. Technically, the prefix operators would be difficult, and the outcome may not be what the programmer anticipated. Doing postfix, but not prefix operators may seem odd. 18 | 19 | #### Conclusion 20 | 21 | We decided to disallow these operators. If folks find scenarios where they need these operators, we might revisit this decision in the future. 22 | 23 | ### `yield` in `try` / `catch` 24 | 25 | Champion Issue: https://github.com/dotnet/csharplang/issues/8414 26 | Spec: https://github.com/dotnet/csharplang/pull/8413 27 | 28 | The proposal is to allow `yield` inside `try`/`catch` blocks in iterators, which is a longstanding user request. There are challenges, both technically and in matching programmer expectations. These particularly arise during `dispose`. The proposal is for only `finally` blocks, and not `catch` blocks to execute during dispose, even when an error is thrown in the `finally` block. 29 | 30 | We went through the details of the behavior, and there are concerns that the programmer may expect `catch` to be executed during dispose. We also discussed the behavior of `yield` during dispose. 31 | 32 | No conclusion was reached. We'll reconsider this in a future meeting after offline work and discussions. 33 | 34 | -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-10-30.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for October 30th, 2024 2 | 3 | ## Agenda 4 | 5 | - [Extensions](#extensions) 6 | 7 | ## Quote of the Day 8 | 9 | - "Part of me wants to trust you , but part of me does not" "I would recommend not" 10 | 11 | ## Discussion 12 | 13 | ### Extensions 14 | 15 | Champion issue: https://github.com/dotnet/csharplang/issues/5497 16 | Documents: 17 | * https://github.com/dotnet/csharplang/blob/e84c2c9711c269243bb2084700512e3f002fec8b/meetings/working-groups/extensions/extensions-an-evolution-of-extension-methods.md 18 | * https://github.com/dotnet/csharplang/blob/e84c2c9711c269243bb2084700512e3f002fec8b/meetings/working-groups/extensions/compromise-design-for-extensions.md 19 | 20 | Today, we took a look at another set of proposals around moving forward on extension types; one taking a more member-centric approach, and the other taking a more type-centric 21 | approach. These proposals also tried to lay out visions for how we might balance tradeoffs. Most the meeting was simply spent reading over and clarifying these proposals. We 22 | also went and collected some statistics around extensions from a few popular libraries, using https://github.com/DustinCampbell/ExtensionMethodDumper. This data covers how many 23 | types are used as a `this` parameter in a given extension type. If we then assume that each of those static classes would need to be split up into extension types for each receiver, 24 | we get: 25 | 26 | * .NET libraries: 496 types goes to 1165 types. Ratio: 2.35 27 | * ASP.NET: 536 types goes to 640: Ratio 1.19 28 | * Roslyn: 782 types goes to 1753 types: Ratio 2.24 29 | * FluentAssertions: 43 types goes to 170 types: Ratio 3.95 30 | 31 | FluentAssertions is a particular outlier in our data here. More than half of that increase comes from a single type, `FluentAssertions.AssertionExtensions`, which has 85 receiver 32 | types on 97 methods. 33 | 34 | Another point that was brought up during the meeting is that we're trying to weigh several different types of "complexity", given our existing language. A type-based extension 35 | world would very likely require fewer overall concepts in the language, if we were starting from scratch. However, we're not starting from scratch; we're starting from C# as it 36 | exists. We already have member-based approaches in the language, and repurposing them may give us a future with a lower concept count given where we're starting. 37 | 38 | This gives us a lot more to think about, so we'll come back in a couple of weeks to discuss yet again. 39 | -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-11-04-patterns.md: -------------------------------------------------------------------------------- 1 | Levi [pointed out](https://github.com/dotnet/roslyn/issues/75506) that many users misunderstand the precedence of `not` and `or` pattern combinators and write faulty code as a result. 2 | He found many instances on GitHub and internally. 3 | 4 | For example: `is not 42 or 43` or `is not null or Type`. 5 | In such cases, the `or` pattern is superfluous. 6 | The user most likely intended to write `is not (42 or 43)` or `is not (null or Type)` instead. 7 | 8 | We considered two possible solutions: 9 | 1. a syntax analyzer that would require parens on either the `not` or around the `or`, so that precedence is explicit 10 | 2. a compiler diagnostic when we can detect that the `or` was redundant in a `not ... or ...` pattern (the goal would be to catch the most common cases, not necessarily 100%) 11 | 12 | I'm pursuing the latter (PR). 13 | The diagnostic is implemented as a regular warning, so it introduces a compat break. 14 | For example: `is not 42 or 43 // warning: the pattern 43 is redundant. Did you mean to parenthesize the `or` pattern?` 15 | 16 | Note: we're okay with catching specific/known bad patterns, and do not require to catch every possible bad pattern. 17 | 18 | Few questions: 19 | 1. confirm we prefer this compiler-based detection over an analyzer 20 | 2. confirm that a regular warning (ie. compat break) is preferrable to a warning-wave warning or a LangVer-gated warning 21 | 22 | 23 | Note: here are some examples where the `or` pattern is not redundant, which Levi saw in the wild and internally: 24 | `is not BaseType or DerivedType` 25 | `is not bool or true` 26 | `is not object or { Prop: condition }` 27 | `is not { Prop1: condition } or { Prop2: condition }` 28 | `is not Type or Type { Prop: condition }` 29 | -------------------------------------------------------------------------------- /meetings/2024/LDM-2024-11-04.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for November 4th, 2024 2 | 3 | ## Agenda 4 | 5 | - [`not` and `or` patterns](#not-and-or-patterns) 6 | - [Notes on notes](#notes-on-notes) 7 | 8 | ## Quote of the Day 9 | 10 | - "Whoever fixed the team room, thanks for helping it see sharp." "[unamused] No" 11 | 12 | ## Discussion 13 | 14 | ### `not` and `or` patterns 15 | 16 | Issue: https://github.com/dotnet/roslyn/issues/75506 17 | Document: [LDM-2024-11-04-patterns.md](LDM-2024-11-04-patterns.md) 18 | 19 | Today, we took a look at an issue with precedence in `not` patterns, when combined with `or` patterns. This is an area where unfortunate Englishisms get in the way of understanding 20 | syntax; when a native English-speaking person says "x is not 1 or 2", they usually mean that x is not 1, and it's also not 2. However, C# uses the same precedence as 21 | the standard unary operators for the pattern operators, so the same thing written in a pattern actually means `x is (not 1) or 2`. Our initial hope was that this would not be a 22 | major issue. However, we now have good evidence that it is; in internal scans, the error rate was nearly 90%. While we certainly can't go change the precedence from the past, we 23 | think that we can detect this and introduce a warning for the scenario. We will issue a warning when a `not` pattern causes a subsequent `or` pattern to be subsumed; while we 24 | wouldn't mind extending subsumption to an entire pattern, not just for this specific scenario, we think that will be significantly more complicated, and we don't want to delay 25 | fixing this. 26 | 27 | #### Conclusion 28 | 29 | We will add a warning for when a `not` pattern causes a subsequent `or` pattern to be subsumed. 30 | 31 | ### Notes on notes 32 | 33 | The outcome of this session was a restructure of how we approach record-keeping on csharplang. The results were documented in the process changes in 34 | [this PR](https://github.com/dotnet/csharplang/pull/8578), with the goal to improve the visibility of issue status on the repo. 35 | -------------------------------------------------------------------------------- /meetings/2025/LDM-2025-01-13.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for January 13th, 2025 2 | 3 | ## Agenda 4 | 5 | - [Discriminated Unions](#discriminated-unions) 6 | 7 | ## Quote of the Day 8 | 9 | - "I'm apparently nothing" 10 | 11 | ## Discussion 12 | 13 | ### Discriminated Unions 14 | 15 | Champion issue: https://github.com/dotnet/csharplang/issues/8928 16 | Proposal: https://github.com/dotnet/csharplang/blob/b6d1f4b3d132ce648299c75f3b9e2961151996b0/proposals/TypeUnions.md 17 | Working Group Status: https://github.com/dotnet/csharplang/blob/b6d1f4b3d132ce648299c75f3b9e2961151996b0/meetings/working-groups/discriminated-unions/Union%20implementation%20challenges.md 18 | 19 | Today we heard from the discriminated unions working group, which has been hard at work exploring the various tradeoffs of how 20 | different types of union structures can be implemented in C#. We started with a refresher of the various options, and worked in 21 | explanations of the tradeoffs the group has discovered. On the whole, we agree with the conclusions of the group; there is some 22 | difference in opinion on the severity of some of the pitfalls, such as the `OfType()` issue in adhoc unions, but 23 | we don't have any additional cases or examples to add to the group's conclusions. We are very much in favor of proceeding with a 24 | single part of the proposal; while we want to keep the other parts in mind during design to ensure that we can add them at a later 25 | date and have them still feel at home in the language, we view unions as a feature that we can and should deliver over time, rather 26 | than all at once, much as we have done with patterns. Therefore, we will proceed with deep design work on just class unions for 27 | now, drilling deep into just that section and working on a design that has the detail level necessary to be implemented in the 28 | language. We want to make sure that, even if v1 of the feature doesn't have a story to grow from a simple union declaration to full 29 | classes with the ability to declare members, implement interfaces, etc., that there is a plan for how to get that full 30 | functionality in the future. 31 | 32 | #### Conclusion 33 | 34 | We will proceed with in-depth design work on class unions. 35 | -------------------------------------------------------------------------------- /meetings/2025/LDM-2025-03-19.md: -------------------------------------------------------------------------------- 1 | # C# Language Design Meeting for March 19th, 2025 2 | 3 | ## Agenda 4 | 5 | - [Readonly setters on non-variables](#readonly-setters-on-non-variables) 6 | 7 | ## Quote of the Day 8 | 9 | - "Sorry for the shorter meeting today" 10 | 11 | ## Discussion 12 | 13 | ### Readonly setters on non-variables 14 | 15 | Champion issue: https://github.com/dotnet/csharplang/issues/9174 16 | Specification: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/readonly-setter-calls-on-non-variables.md 17 | 18 | Today, we looked at a proposal to lift an error scenario around `readonly`. One interesting thing with this is that we're already in an 19 | inconsistent state; we permit `readonly` setters to be called on the result of a `ref`-returning method, for example. This is likely an 20 | unintended "bug" in the implementation of `ref`-readonly methods, but at initial glance we could just make that the explicitly-allowed 21 | behavior and standardize on that. 22 | 23 | There was some discussion on named indexers; this is one of the primary use cases given to enable this language feature, but is that 24 | motivation enough for this language feature? Or should we just do named indexers directly? However, as we previously noted, we want the 25 | compiler to get to a consistent state; there are a few other motivating scenarios that we can discuss extending this feature to as well 26 | in future design sessions. 27 | 28 | We also brought up some concerns that this could potentially enable new dropped value scenarios, where the struct is creating a new 29 | reference type under the hood and then being dropped. However, there's nothing unique to `struct`s here; the same type of issue as might 30 | happen when a user uses an expression-bodied property of `{ get; } = new();` instead. 31 | 32 | Given all of this, we think that we're fine with this proposal to move forward. We'll put it in "Any Time" for now, and revisit potential 33 | extensions to it at a later date. 34 | 35 | #### Conclusion 36 | 37 | Proposal is accepted, put into "Any Time". 38 | -------------------------------------------------------------------------------- /meetings/working-groups/discriminated-unions/DU-2022-11-07.md: -------------------------------------------------------------------------------- 1 | ## Notes for November 7th, 2022 2 | 3 | As a reminder, we use [this syntax](DU-2022-10-31.md#pseudo-syntax) for describing unions forms. 4 | 5 | ### Conversions 6 | 7 | Pickup up from last week, we talked about equivalency again. This time, we started by focusing on the differences between `union (A | B)` (an anonymous union of types) and 8 | `union NamedAOrB (A | B)` (a named union of types). We do generally think that `union (A | B)` and `union (B | A)` should at least be implicitly convertible, if not identical, 9 | and that has implications on the grow up story. Much like with tuples, we don't think anonymous union types belong in public APIs, except in cases like `Zip` where the 10 | implementation detail of the tuple is the _purpose_ of the API (in other words, when the likelihood of adding or removing a new element is nonexistent). Tuples that need to 11 | be in public API generally want to grow up to be positional records, and we might need something similar here for untagged named unions. In thinking about it more, though, 12 | we're not certain of the need for exporting this type of union. It would have limitations, such as the inability to have two different cases with the same type (a string result 13 | or string error, for example, couldn't be represented without a separate tag), so it's possible that the roles proposal is enough for us here. Something like 14 | `role NamedAOrB : (A | B);` would give a name to the case, give us equivalency with the underlying type, and maintain discouragement of putting untagged unions in public 15 | type hierarchies. 16 | 17 | ### Switching on unions 18 | 19 | We considered a few different ways that users might want to pattern match against anonymous unions of types: 20 | 21 | ```cs 22 | void M((int|string) x) 23 | { 24 | object o = x; 25 | _ = o switch 26 | { 27 | (int|string) => 0, 28 | _ => 0 29 | }; 30 | _ = o switch 31 | { 32 | int or string => 1, 33 | _ => 1 34 | }; 35 | _ = o switch 36 | { 37 | int => 2, 38 | string => 2, 39 | _ => 2, 40 | }; 41 | 42 | // Switch on x 43 | _ = x switch 44 | { 45 | int => 2, // Could use x.IsTypeOf 46 | string => 2, 47 | _ => 2, 48 | }; 49 | } 50 | ``` 51 | 52 | There are a few ways this could work: 53 | 54 | 1. Erase the union, and have it be object. Type tests are emitted as today. 55 | 2. Check for an IsOneOf marker interface. Would have to always check, behavior change on recompile. 56 | 3. When switching on the union itself, call an `IsType` method. 57 | 4. Have the runtime participate in boxing, throwing away a wrapper type. 58 | 59 | We don't have any decisions yet, we're still exploring the space. We'll keep exploring further. 60 | -------------------------------------------------------------------------------- /meetings/working-groups/roles/extension-wg-2024-06-14.md: -------------------------------------------------------------------------------- 1 | # Extensions WG 2024-06-14 2 | 3 | Agenda 4 | - type erasure 5 | 6 | TL;DR: we'll pursue the attribute with typeof-like string. 7 | 8 | ## Type erasure 9 | 10 | We did a quick recap of various options we'd considered so far, and explored using an attribute 11 | with a string serialization to represent the erased types. 12 | 13 | 1. modopts 14 | 2. generic attribute 15 | 3. attribute+typeof 16 | 4. parallel method 17 | 5. typeref/blobs 18 | 19 | ### Attribute with typeof-like string 20 | 21 | The main problem is how to represent type parameters, since they are currently disallowed in typeof inside attributes. 22 | We could extend the typeof format with existing convention "!N" (type parameters), "!!N" (method type parameters), stopping at first container (method or type) when resolving. 23 | We would use a `string` instead of a `Type`: `ExtensionAttribute(string encodedInformation)`. 24 | ```csharp 25 | // source 26 | void M(C>) 27 | 28 | // metadata 29 | void M([ExtensionAttribute("E")] C) 30 | ``` 31 | 32 | There are some concerns with re-hydration reliability, but those are not worse than what typeof in attributes already encounters. 33 | In terms of specification, we would just say we use the existing (not well-specified) format from typeof and just add the type parameter case. 34 | For reflection users, this string would be less useful than a `Type`. Maybe some helper APIs could be offered (somewhere outside the compiler-synthesized attribute and not in roslyn). 35 | This format feels verbose (compared to typerefs), but it seems the most feasible and comparatively simpler overall compared to other options. 36 | 37 | Encoding one attribute per typed entity (return type, parameter type, constraint type) fits with current codegen for tuple names, nullability, dynamic, etc. We will let the runtime team know in case this is a major concern. 38 | 39 | We need separate encoding for tuple names, nullability on non-erased type. This can be stored in the attribute itself. 40 | ```csharp 41 | class ExtensionAttribute 42 | { 43 | ExtensionAttribute(string) { } 44 | Nullability { get; } 45 | TupleNames { get; } 46 | Dynamic { get; } 47 | } 48 | ``` 49 | 50 | As for other such compiler-generated attributes, we'll disallow direct usage of this attribute in source. 51 | -------------------------------------------------------------------------------- /meetings/working-groups/roles/extension-wg-2024-06-21.md: -------------------------------------------------------------------------------- 1 | # Extensions WG 2024-06-21 2 | 3 | - update on instance invocation 4 | - open issue: what kind of type is an extension type? 5 | - spec: conversions, operators, adapting to existing type kind rules, any updates from design review (Mads) 6 | 7 | # Instance invocation 8 | 9 | See description in https://github.com/dotnet/roslyn/pull/74012 10 | 11 | We'll have follow-up issue for nullability of the extra parameter. 12 | We'll have follow-up issue for capturing the receiver when it is a type parameter. 13 | 14 | Note: When implementing interfaces, a modopt(ExtensionAttribute) could be brought into the picture and cause a conflict/ambiguity. 15 | 16 | ## Open issue: what kind of type is an extension type? 17 | 18 | Many sections of the spec need to consider the kind of type. Consider a few examples: 19 | - the spec for a conditional element access `P?[A]B` 20 | considers whether `P` is a nullable value type. So it will need to handle the case 21 | where `P` is an instance of an extension type on a nullable value type, 22 | - the spec for an object creation considers whether the type is 23 | a value_type, a type_parameter, a class_type or a struct_type, 24 | - the spec for satisfying constraints also consider what kind of type were dealing with. 25 | 26 | It may be possible to address all those cases without changing each such section of the spec, 27 | but rather by adding general rules ("an extension on a class type is considered a class type" or some such). 28 | 29 | 1. extension type on class type is a class type, on a struct type is a struct type, on a type parameter is considered a type parameter, ... (not sure how to word this, maybe "for purpose of") 30 | 2. but nullable value type needs to be handled case by case. System.Nullable<...> 31 | 3. are there other cases we need to consider (keep an eye out) 32 | 33 | explicit extension E for T { void M(); } 34 | new C().M(); 35 | new S().M(); 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /meetings/working-groups/roles/extensions-wg-2023-06-07.md: -------------------------------------------------------------------------------- 1 | # Extensions 2023-06-07 2 | 3 | ## Reviewing the "invocation expression", "member access" and "extension invocation" sections 4 | 5 | We reviewed the proposals in PR https://github.com/dotnet/csharplang/pull/7179 and discussed some open issues. 6 | 7 | ### Invoking members from extended type 8 | 9 | The first issue is that we want to access members from the extended type on a type or value of an extension type. 10 | 11 | ```csharp 12 | extension E for C 13 | { 14 | void M() 15 | { 16 | this.MethodFromUnderlying(); // problem 17 | MethodFromUnderlying(); // problem 18 | } 19 | } 20 | ``` 21 | 22 | The current proposal had a bullet in "member access" 23 | which would make member access scenarios work for non-invocations, 24 | but that left invocations and simple name scenarios unsupported. 25 | 26 | Decision: we want those scenarios to work and we can achieve that 27 | by modifying "member lookup" to also find members from the underlying type. 28 | The "member lookup" section already handles lookups 29 | 30 | ### Pattern-based method binding 31 | 32 | The second issue is that the proposed rules raise a question about how pattern-based invocations, 33 | such as the one involved in deconstruction. 34 | 35 | For instance, should the following work? 36 | 37 | ```csharp 38 | implicit extension E for C 39 | { 40 | public dynamic Deconstruct { get { ... } } 41 | } 42 | 43 | class C 44 | { 45 | void M() 46 | { 47 | (int i, int j) = this; 48 | } 49 | } 50 | ``` 51 | 52 | Decision: If the scenario allowed instance properties today, then extension properties should work, if not, then not. 53 | So, given that an instance `Deconstruct` property would not participate in deconstruction today, 54 | we don't want an extension `Deconstruct` property to participate either. 55 | 56 | Any scenario that allowed extension methods should allow methods from extension types to participate. 57 | This means we'll need to review all pattern-based sections of the spec to come up with some language 58 | to only bind to methods in the extension type case. Maybe something like "Do a member access and if that resolves to a method, then ..." 59 | or "if the expression ... resolves at compile-time to a unique instance or extension method or extension type method, that expression is evaluated". 60 | 61 | Also, we'll need to make decisions for 62 | non-invocation members, such as the `Current` property involved in a `foreach`, as those were not previously 63 | covered by extension methods. 64 | 65 | ## Forward compatible emit strategy for interface support 66 | 67 | We briefly reviewed an alternative to the `ref struct` approach that is currently proposed. 68 | We will need to experiment and flesh out a proposal. 69 | -------------------------------------------------------------------------------- /meetings/working-groups/roles/extensions-wg-2024-08-09.md: -------------------------------------------------------------------------------- 1 | # Extensions WG 2024-08-09 2 | 3 | ## Conversions 4 | 5 | We reviewed proposed approach for conversions: 6 | - extend existing conversions rather than introduce a new "extension conversion 7 | - extend categories of "reference types", "value types", "nullable value types", "enum types" 8 | - follow-ups: non-transitive identity conversion (`EInt1 => EInt2`), user-defined conversions 9 | 10 | ## Reference nullability 11 | 12 | Allowing top-level nullability on underlying types is tempting for implicit scenarios, but it's going to cause problems on explicit scenarios. 13 | If we define `explicit extension E for object? { }`, then do you get to say `E?`? Also would `E` be considered annotated or not? 14 | This is already tracked as an open issue to investigate further. 15 | 16 | ## Differences between extensions and structs you could write today? 17 | 18 | ``` 19 | implicit extension JsonDoc for string { public void ExtensionMember() { } } 20 | ``` 21 | vs. 22 | ``` 23 | struct JsonDoc 24 | { 25 | public static implicit operator string(JsonDoc) 26 | public static implicit operator JsonDoc(string) 27 | } 28 | ``` 29 | 30 | With extensions you get the following benefits: 31 | - identity/standard conversion 32 | - List<[JsonDoc] string> vs. List 33 | - extension conversions 34 | - `"".ExtensionMember()` (by virtue of `implicit`) 35 | 36 | ## Relationship between implicit and explicit? 37 | 38 | Every extensions can be used explicitly, but only implicit ones can come into play implicitly. 39 | 40 | ## Brainstorming on naming extensions 41 | 42 | The name "JsonDoc" brings a mental model of hierarchy or "is-a" relationship. This feels more natural for explicit usages. 43 | But the name "StringExtension" does not bring such a mental model. This feels more natural for implicit usages. 44 | 45 | `JsonDoc s = "";` 46 | `StringExtension s = "";` // weird 47 | 48 | ## Disambiguation for properties 49 | 50 | Allowing implicit extensions to be named explicitly helps for disambiguation. 51 | 52 | `StringExtension.ExtensionMember(receiver, args)` // fallback for extension methods 53 | 54 | ``` 55 | implicit extension StringExtension1 for string { public int Prop { get; set; } } 56 | implicit extension StringExtension2 for string { public int Prop { get; set; } } 57 | 58 | "".Prop // how to disambiguate? 59 | ((StringExtension1)"").Prop 60 | ``` 61 | 62 | ## Concern over type explosions 63 | 64 | ``` 65 | static class MemoryExtension 66 | { 67 | public static void M1(this Type1) 68 | public static void M2(this Type2) 69 | } 70 | ``` 71 | You would need to split this into two extension types. One for Type1 and the other for Type2. 72 | 73 | -------------------------------------------------------------------------------- /proposals/csharp-10.0/extended-property-patterns.md: -------------------------------------------------------------------------------- 1 | # Extended property patterns 2 | 3 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 4 | 5 | Champion issue: 6 | 7 | ## Summary 8 | [summary]: #summary 9 | 10 | Allow property subpatterns to reference nested members, for instance: 11 | ```cs 12 | if (e is MethodCallExpression { Method.Name: "MethodName" }) 13 | ``` 14 | Instead of: 15 | ```cs 16 | if (e is MethodCallExpression { Method: { Name: "MethodName" } }) 17 | ``` 18 | 19 | ## Motivation 20 | [motivation]: #motivation 21 | 22 | When you want to match a child property, nesting another recursive pattern adds too much noise which will hurt readability with no real advantage. 23 | 24 | ## Detailed design 25 | [design]: #detailed-design 26 | 27 | The [*property_pattern*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/patterns.md#property-pattern) syntax is modified as follow: 28 | 29 | ```diff 30 | property_pattern 31 | : type? property_pattern_clause simple_designation? 32 | ; 33 | 34 | property_pattern_clause 35 | : '{' (subpattern (',' subpattern)* ','?)? '}' 36 | ; 37 | 38 | subpattern 39 | - : identifier ':' pattern 40 | + : subpattern_name ':' pattern 41 | ; 42 | 43 | +subpattern_name 44 | + : identifier 45 | + | subpattern_name '.' identifier 46 | + ; 47 | ``` 48 | 49 | The receiver for each name lookup is the type of the previous member *T0*, starting from the *input type* of the *property_pattern*. if *T* is a nullable type, *T0* is its underlying type, otherwise *T0* is equal to *T*. 50 | 51 | For example, a pattern of the form `{ Prop1.Prop2: pattern }` is exactly equivalent to `{ Prop1: { Prop2: pattern } }`. 52 | 53 | Note that this will include the null check when *T* is a nullable value type or a reference type. This null check means that the nested properties available will be the properties of *T0*, not of *T*. 54 | 55 | Repeated member paths are allowed. The compilation of pattern matching can take advantage of common parts of patterns. 56 | -------------------------------------------------------------------------------- /proposals/csharp-11.0/new-line-in-interpolation.md: -------------------------------------------------------------------------------- 1 | # Allow new-lines in all interpolations 2 | 3 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 4 | 5 | Champion issue: 6 | 7 | * [x] Proposed 8 | * [x] Implementation: https://github.com/dotnet/roslyn/pull/56853 9 | * [x] Specification: this file. 10 | 11 | ## Summary 12 | [summary]: #summary 13 | 14 | The language today treats non-verbatim and verbatim interpolated strings (`$""` and `$@""` respectively) differently. The primary *sensible* difference for these is that a non-verbatim interpolated string works like a normal string and cannot contain newlines in its text segments, and must instead use escapes (like `\r\n`). Conversely, a verbatim interpolated string can contain newlines in its text segments (like a verbatim string), and doesn't escape newlines or other character (except for `""` to escape a quote itself). 15 | 16 | This is all reasonable and will not change with this proposal. 17 | 18 | What is unreasonable today is that we extend the restriction on 'no newlines' in a non-verbatim interpolated string *beyond* its text segments into the *interpolations* themselves. This means, for example, that you cannot write the following: 19 | 20 | ```c# 21 | var v = $"Count is\t: { this.Is.A.Really(long(expr)) 22 | .That.I.Should( 23 | be + able)[ 24 | to.Wrap()] }."; 25 | ``` 26 | 27 | Ultimately, the 'interpolation must be on a single line itself' rule is just a restriction of the current implementation. That restriction really isn't necessary, and can be annoying, and would be fairly trivial to remove (see work https://github.com/dotnet/roslyn/pull/54875 to show how). In the end, all it does is force the dev to place things on a single line, or force them into a verbatim interpolated string (both of which may be unpalatable). 28 | 29 | The interpolation expressions themselves are not text, and shouldn't be beholden to any escaping/newline rules therin. 30 | 31 | ## Specification change 32 | 33 | ```diff 34 | single_regular_balanced_text_character 35 | - : '' 36 | - | '' 37 | + : 38 | + | comment 39 | ; 40 | ``` 41 | 42 | ## LDM Discussions 43 | 44 | https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-09-20.md 45 | -------------------------------------------------------------------------------- /proposals/csharp-13.0/esc-escape-sequence.md: -------------------------------------------------------------------------------- 1 | 2 | # String/Character escape sequence `\e` 3 | 4 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 5 | 6 | Champion issue: 7 | 8 | ## Summary 9 | An addition of the string/character escape sequence `\e` as a shortcut/short-hand replacement 10 | for the character code point `0x1b`, commonly known as the `ESCAPE` (or `ESC`) character. 11 | This character is currently accessible using one of the following escape sequences: 12 | - `\u001b` 13 | - `\U0000001b` 14 | - `\x1b` (not recommended, see the picture attached at the bottom.) 15 | 16 | With the implementation of this proposal, the following assertions should be true: 17 | ```csharp 18 | char escape_char = '\e'; 19 | 20 | Assert.IsTrue(escape_char == (char)0x1b, "..."); 21 | Assert.IsTrue(escape_char == '\u001b', "..."); 22 | Assert.IsTrue(escape_char == '\U0000001b', "..."); 23 | Assert.IsTrue(escape_char == '\x1b', "..."); 24 | ``` 25 | 26 | ## Detailed design 27 | The language syntax specification is changed as follows in section 28 | [6.4.5.5](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/lexical-structure.md#6455-character-literals): 29 | 30 | ```diff 31 | fragment Simple_Escape_Sequence 32 | - : '\\\'' | '\\"' | '\\\\' | '\\0' | '\\a' | '\\b' | '\\f' | '\\n' | '\\r' | '\\t' | '\\v' 33 | + : '\\\'' | '\\"' | '\\\\' | '\\0' | '\\a' | '\\b' | '\\f' | '\\n' | '\\r' | '\\t' | '\\v' | '\\e' 34 | ; 35 | ``` 36 | As well as the addition of the **last line** to the following table in the specifications: 37 | 38 | > A simple escape sequence represents a Unicode character, as described in the table below. 39 | > 40 | > | **Escape sequence** | **Character name** | **Unicode code point** | 41 | > |---------------------|--------------------|--------------------| 42 | > | `\'` | Single quote | U+0027 | 43 | > | ... | ... | ... | 44 | > | `\e` | Escape character | U+001B | 45 | > 46 | > The type of a *Character_Literal* is `char`. 47 | -------------------------------------------------------------------------------- /proposals/csharp-6.0/empty-params-array.md: -------------------------------------------------------------------------------- 1 | # Empty array for zero arguments passed to params parameter 2 | 3 | We use Array.Empty() to create a zero-element array to pass to a params method when no arguments correspond. 4 | The language spec requires a new array, so it is a language change. 5 | This is a placeholder for the specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-6.0/enum-base-type.md: -------------------------------------------------------------------------------- 1 | ## Enum Base Type 2 | 3 | In C# 6.0 we relaxed the syntax of an enum base type to be a type syntax, but require that it bind to one of a specified set of types. So `System.Int32` is permitted. But the spec has not been updated; it still requires one of a set of keywords for the base. 4 | 5 | This is a placeholder for a specification of that change. 6 | -------------------------------------------------------------------------------- /proposals/csharp-6.0/struct-autoprop-init.md: -------------------------------------------------------------------------------- 1 | # Relaxed rules for auto-properties in structs 2 | 3 | Before C# 6.0 you could not write code like this: 4 | 5 | ```csharp 6 | struct S 7 | { 8 | int X { get; set; } 9 | int Y { get; set; } 10 | public S(int x, int y) 11 | { 12 | this.X = x; 13 | this.Y = y; 14 | } 15 | } 16 | ``` 17 | 18 | ```none 19 | error CS0188: The 'this' object cannot be used before all of its fields are assigned to 20 | error CS0843: Backing field for automatically implemented property 'S.X' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer. 21 | error CS0843: Backing field for automatically implemented property 'S.Y' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer. 22 | ``` 23 | 24 | A workaround was to invoke the default constructor: 25 | 26 | ```csharp 27 | struct S 28 | { 29 | int X { get; set; } 30 | int Y { get; set; } 31 | public S(int x, int y) : this() 32 | { 33 | this.X = x; 34 | this.Y = y; 35 | } 36 | } 37 | ``` 38 | 39 | or to initialize this to the default value: 40 | 41 | ```csharp 42 | struct S 43 | { 44 | int X { get; set; } 45 | int Y { get; set; } 46 | public S(int x, int y) 47 | { 48 | this = default(S); 49 | this.X = x; 50 | this.Y = y; 51 | } 52 | } 53 | ``` 54 | 55 | Unfortunately, both methods effectively disabled definite assignment analysis for instance fields for the given constructor. 56 | 57 | C# 6.0 relaxes these rules by tracking assignments to instance auto-properties as if they were assignments to their backing fields, so the code in the beginning of this section is now valid. 58 | -------------------------------------------------------------------------------- /proposals/csharp-7.0/binary-literals.md: -------------------------------------------------------------------------------- 1 | # Binary literals 2 | 3 | Champion issue: 4 | 5 | There’s a relatively common request to add binary literals to C# and VB. For bitmasks (e.g. flag enums) this seems genuinely useful, but it would also be great just for educational purposes. 6 | 7 | Binary literals would look like this: 8 | 9 | ```csharp 10 | int nineteen = 0b10011; 11 | ``` 12 | 13 | Syntactically and semantically they are identical to hexadecimal literals, except for using `b`/`B` instead of `x`/`X`, having only digits `0` and `1` and being interpreted in base 2 instead of 16. 14 | 15 | There’s little cost to implementing these, and little conceptual overhead to users of the language. 16 | 17 | ## Syntax 18 | 19 | The grammar would be as follows: 20 | 21 | ```antlr 22 | integer-literal: 23 | : ... 24 | | binary-integer-literal 25 | ; 26 | binary-integer-literal: 27 | : `0b` binary-digits integer-type-suffix-opt 28 | | `0B` binary-digits integer-type-suffix-opt 29 | ; 30 | binary-digits: 31 | : binary-digit 32 | | binary-digits binary-digit 33 | ; 34 | binary-digit: 35 | : `0` 36 | | `1` 37 | ; 38 | ``` 39 | -------------------------------------------------------------------------------- /proposals/csharp-7.0/digit-separators.md: -------------------------------------------------------------------------------- 1 | # Digit separators 2 | 3 | Champion issue: 4 | 5 | Being able to group digits in large numeric literals would have great readability impact and no significant downside. 6 | 7 | Adding binary literals (#215) would increase the likelihood of numeric literals being long, so the two features enhance each other. 8 | 9 | We would follow Java and others, and use an underscore `_` as a digit separator. It would be able to occur everywhere in a numeric literal (except as the first and last character), since different groupings may make sense in different scenarios and especially for different numeric bases: 10 | 11 | ```csharp 12 | int bin = 0b1001_1010_0001_0100; 13 | int hex = 0x1b_a0_44_fe; 14 | int dec = 33_554_432; 15 | int weird = 1_2__3___4____5_____6______7_______8________9; 16 | double real = 1_000.111_1e-1_000; 17 | ``` 18 | 19 | Any sequence of digits may be separated by underscores, possibly more than one underscore between two consecutive digits. They are allowed in decimals as well as exponents, but following the previous rule, they may not appear next to the decimal (`10_.0`), next to the exponent character (`1.1e_1`), or next to the type specifier (`10_f`). When used in binary and hexadecimal literals, they may not appear immediately following the `0x` or `0b`. 20 | 21 | The syntax is straightforward, and the separators have no semantic impact - they are simply ignored. 22 | 23 | This has broad value and is easy to implement. 24 | -------------------------------------------------------------------------------- /proposals/csharp-7.0/expression-bodied-everything.md: -------------------------------------------------------------------------------- 1 | ## Expression Bodied Everything 2 | 3 | Champion issue: 4 | 5 | In C# 7.0, we added support for expression-bodied constructors, destructors, and accessors. This is a placeholder for the specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-7.0/out-var.md: -------------------------------------------------------------------------------- 1 | # Out variable declarations 2 | 3 | Champion issue: 4 | 5 | The *out variable declaration* feature enables a variable to be declared at the location that it is being passed as an `out` argument. 6 | 7 | ```antlr 8 | argument_value 9 | : 'out' type identifier 10 | | ... 11 | ; 12 | ``` 13 | 14 | A variable declared this way is called an *out variable*. You may use the contextual keyword `var` for the variable's type. The scope will be the same as for a *pattern-variable* introduced via pattern-matching. 15 | 16 | According to Language Specification (section 7.6.7 Element access) the argument-list of an element-access (indexing expression) does not contain ref or out arguments. However, they are permitted by the compiler for various scenarios, for example indexers declared in metadata that accept `out`. 17 | 18 | Within the scope of a local variable introduced by an argument_value, it is a compile-time error to refer to that local variable in a textual position that precedes its declaration. 19 | 20 | It is also an error to reference an implicitly-typed (§8.5.1) out variable in the same argument list that immediately contains its declaration. 21 | 22 | Overload resolution is modified as follows: 23 | 24 | We add a new conversion: 25 | 26 | > There is a *conversion from expression* from an implicitly-typed out variable declaration to every type. 27 | 28 | Also 29 | 30 | > The type of an explicitly-typed out variable argument is the declared type. 31 | 32 | and 33 | 34 | > An implicitly-typed out variable argument has no type. 35 | 36 | The *conversion from expression* from an implicitly-typed out variable declaration is not considered better than any other *conversion from expression*. 37 | 38 | The type of an implicitly-typed out variable is the type of the corresponding parameter in the signature of the method selected by overload resolution. 39 | 40 | The new syntax node `DeclarationExpressionSyntax` is added to represent the declaration in an out var argument. 41 | -------------------------------------------------------------------------------- /proposals/csharp-7.0/ref-locals-returns.md: -------------------------------------------------------------------------------- 1 | ## Ref Locals and Returns 2 | 3 | Champion issue: 4 | 5 | In C# 7.0 we added support for *ref locals and ref returns*. This is a placeholder for its specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-7.0/throw-expression.md: -------------------------------------------------------------------------------- 1 | # Throw expression 2 | 3 | Champion issue: 4 | 5 | We extend the set of expression forms to include 6 | 7 | ```antlr 8 | throw_expression 9 | : 'throw' null_coalescing_expression 10 | ; 11 | 12 | null_coalescing_expression 13 | : throw_expression 14 | ; 15 | ``` 16 | 17 | The type rules are as follows: 18 | 19 | - A *throw_expression* has no type. 20 | - A *throw_expression* is convertible to every type by an implicit conversion. 21 | 22 | A *throw expression* throws the value produced by evaluating the *null_coalescing_expression*, which must denote a value of the class type `System.Exception`, of a class type that derives from `System.Exception` or of a type parameter type that has `System.Exception` (or a subclass thereof) as its effective base class. If evaluation of the expression produces `null`, a `System.NullReferenceException` is thrown instead. 23 | 24 | The behavior at runtime of the evaluation of a *throw expression* is the same as specified for a *throw statement* ([§12.10.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12106-the-throw-statement)). 25 | 26 | The flow-analysis rules are as follows: 27 | 28 | - For every variable *v*, *v* is definitely assigned before the *null_coalescing_expression* of a *throw_expression* iff it is definitely assigned before the *throw_expression*. 29 | - For every variable *v*, *v* is definitely assigned after *throw_expression*. 30 | 31 | A *throw expression* is permitted in only the following syntactic contexts: 32 | - As the second or third operand of a ternary conditional operator `?:` 33 | - As the second operand of a null coalescing operator `??` 34 | - As the body of an expression-bodied lambda or method. 35 | -------------------------------------------------------------------------------- /proposals/csharp-7.0/tuples.md: -------------------------------------------------------------------------------- 1 | ## Tuples 2 | 3 | Champion issue: 4 | 5 | In C# 7.0 we added support for *tuples*. This is a placeholder for its specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-7.1/README.md: -------------------------------------------------------------------------------- 1 | 2 | # C# 7.1 3 | 4 | - [Async Main](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md) 5 | - [Default Expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/target-typed-default.md) 6 | - [Infer tuple names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md) 7 | - [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/generics-pattern-match.md) 8 | 9 | -------------------------------------------------------------------------------- /proposals/csharp-7.1/generics-pattern-match.md: -------------------------------------------------------------------------------- 1 | # pattern-matching with generics 2 | 3 | Champion issue: 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | The specification for the existing C# as operator ([§11.11.12](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111112-the-as-operator)) permits there to be no conversion between the type of the operand and the specified type when either is an open type. However, in C# 7 the `Type identifier` pattern requires there be a conversion between the type of the input and the given type. 9 | 10 | We propose to relax this and change `expression is Type identifier`, in addition to being permitted in the conditions when it is permitted in C# 7, to also be permitted when `expression as Type` would be allowed. Specifically, the new cases are cases where the type of the expression or the specified type is an open type. 11 | 12 | ## Motivation 13 | [motivation]: #motivation 14 | 15 | Cases where pattern-matching should "obviously" be permitted currently fail to compile. See, for example, https://github.com/dotnet/roslyn/issues/16195. 16 | 17 | ## Detailed design 18 | [design]: #detailed-design 19 | 20 | We change the paragraph in the pattern-matching specification (the proposed addition is shown in bold): 21 | 22 | > Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. A value of static type `E` is said to be *pattern compatible* with the type `T` if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from `E` to `T`**, or if either `E` or `T` is an open type**. It is a compile-time error if an expression of type `E` is not pattern compatible with the type in a type pattern that it is matched with. 23 | 24 | ## Drawbacks 25 | [drawbacks]: #drawbacks 26 | 27 | None. 28 | 29 | ## Alternatives 30 | [alternatives]: #alternatives 31 | 32 | None. 33 | 34 | ## Unresolved questions 35 | [unresolved]: #unresolved-questions 36 | 37 | None. 38 | 39 | ## Design meetings 40 | 41 | LDM considered this question and felt it was a bug-fix level change. We are treating it as a separate language feature because just making the change after the language has been released would introduce a forward incompatibility. Using the proposed change requires that the programmer specify language version 7.1. 42 | -------------------------------------------------------------------------------- /proposals/csharp-7.2/leading-separator.md: -------------------------------------------------------------------------------- 1 | # Allow digit separator after 0b or 0x 2 | 3 | Champion issue: 4 | 5 | In C# 7.2, we extend the set of places that digit separators (the underscore character) can appear in integral literals. [Beginning in C# 7.0, separators are permitted between the digits of a literal](../csharp-7.0/digit-separators.md). Now, in C# 7.2, we also permit digit separators before the first significant digit of a binary or hexadecimal literal, after the prefix. 6 | 7 | ```csharp 8 | 123 // permitted in C# 1.0 and later 9 | 1_2_3 // permitted in C# 7.0 and later 10 | 0x1_2_3 // permitted in C# 7.0 and later 11 | 0b101 // binary literals added in C# 7.0 12 | 0b1_0_1 // permitted in C# 7.0 and later 13 | 14 | // in C# 7.2, _ is permitted after the `0x` or `0b` 15 | 0x_1_2 // permitted in C# 7.2 and later 16 | 0b_1_0_1 // permitted in C# 7.2 and later 17 | ``` 18 | 19 | We do not permit a decimal integer literal to have a leading underscore. A token such as `_123` is an identifier. 20 | -------------------------------------------------------------------------------- /proposals/csharp-7.2/readonly-struct.md: -------------------------------------------------------------------------------- 1 | ## Readonly structs 2 | 3 | In C# 7.2, we added a feature permitting a struct declaration to have the `readonly` modifier. This is a placeholder for that feature's specification. 4 | -------------------------------------------------------------------------------- /proposals/csharp-7.2/ref-extension-methods.md: -------------------------------------------------------------------------------- 1 | ## Ref Extension Methods 2 | 3 | Champion issue: 4 | 5 | In C# 7.2, we added support for *ref extension methods*. This is a placeholder for the feature's specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-7.2/ref-struct-and-span.md: -------------------------------------------------------------------------------- 1 | ## Ref Structs and Span 2 | 3 | In C# 7.2 we added support for *ref struct* types. This is a placeholder for the specification. 4 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/auto-prop-field-attrs.md: -------------------------------------------------------------------------------- 1 | # Auto-Implemented Property Field-Targeted Attributes 2 | 3 | Champion issu: https://github.com/dotnet/csharplang/issues/42 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | This feature intends to allow developers to apply attributes directly to the backing fields of auto-implemented properties. 9 | 10 | ## Motivation 11 | [motivation]: #motivation 12 | 13 | Currently it is not possible to apply attributes to the backing fields of auto-implemented properties. In those cases where the developer must use a field-targeting attribute they are forced to declare the field manually and use the more verbose property syntax. Given that C# has always supported field-targeted attributes on the generated backing field for events it makes sense to extend the same functionality to their property kin. 14 | 15 | ## Detailed design 16 | [design]: #detailed-design 17 | 18 | In short, the following would be legal C# and not produce a warning: 19 | 20 | ```csharp 21 | [Serializable] 22 | public class Foo 23 | { 24 | [field: NonSerialized] 25 | public string MySecret { get; set; } 26 | } 27 | ``` 28 | 29 | This would result in the field-targeted attributes being applied to the compiler-generated backing field: 30 | 31 | ```csharp 32 | [Serializable] 33 | public class Foo 34 | { 35 | [NonSerialized] 36 | private string _mySecretBackingField; 37 | 38 | public string MySecret 39 | { 40 | get { return _mySecretBackingField; } 41 | set { _mySecretBackingField = value; } 42 | } 43 | } 44 | ``` 45 | 46 | As mentioned, this brings parity with event syntax from C# 1.0 as the following is already legal and behaves as expected: 47 | 48 | ```csharp 49 | [Serializable] 50 | public class Foo 51 | { 52 | [field: NonSerialized] 53 | public event EventHandler MyEvent; 54 | } 55 | ``` 56 | 57 | ## Drawbacks 58 | [drawbacks]: #drawbacks 59 | 60 | There are two potential drawbacks to implementing this change: 61 | 62 | 1. Attempting to apply an attribute to the field of an auto-implemented property produces a compiler warning that the attributes in that block will be ignored. If the compiler were changed to support those attributes they would be applied to the backing field on a subsequent recompilation which could alter the behavior of the program at runtime. 63 | 1. The compiler does not currently validate the AttributeUsage targets of the attributes when attempting to apply them to the field of the auto-implemented property. If the compiler were changed to support field-targeted attributes and the attribute in question cannot be applied to a field the compiler would emit an error instead of a warning, breaking the build. 64 | 65 | ## Alternatives 66 | [alternatives]: #alternatives 67 | 68 | ## Unresolved questions 69 | [unresolved]: #unresolved-questions 70 | 71 | ## Design meetings 72 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/enum-delegate-constraints.md: -------------------------------------------------------------------------------- 1 | ## Enum and Delegate type parameter constraint 2 | 3 | Champion issue: 4 | 5 | In C# 7.3, we added support for type parameter constraint keywords `enum` and `delegate`. This is a placeholder for their specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/expression-variables-in-initializers.md: -------------------------------------------------------------------------------- 1 | # Expression variables in initializers 2 | 3 | Champion issue: 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | We extend the features introduced in C# 7 to permit expressions containing expression variables (out variable declarations and declaration patterns) in field initializers, property initializers, ctor-initializers, and query clauses. 9 | 10 | ## Motivation 11 | [motivation]: #motivation 12 | 13 | This completes a couple of the rough edges left in the C# language due to lack of time. 14 | 15 | ## Detailed design 16 | [design]: #detailed-design 17 | 18 | We remove the restriction preventing the declaration of expression variables (out variable declarations and declaration patterns) in a ctor-initializer. Such a declared variable is in scope throughout the body of the constructor. 19 | 20 | We remove the restriction preventing the declaration of expression variables (out variable declarations and declaration patterns) in a field or property initializer. Such a declared variable is in scope throughout the initializing expression. 21 | 22 | We remove the restriction preventing the declaration of expression variables (out variable declarations and declaration patterns) in a query expression clause that is translated into the body of a lambda. Such a declared variable is in scope throughout that expression of the query clause. 23 | 24 | ## Drawbacks 25 | [drawbacks]: #drawbacks 26 | 27 | None. 28 | 29 | ## Alternatives 30 | [alternatives]: #alternatives 31 | 32 | The appropriate scope for expression variables declared in these contexts is not obvious, and deserves further LDM discussion. 33 | 34 | ## Unresolved questions 35 | [unresolved]: #unresolved-questions 36 | 37 | - [ ] What is the appropriate scope for these variables? 38 | 39 | ## Design meetings 40 | 41 | None. 42 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/improved-overload-candidates.md: -------------------------------------------------------------------------------- 1 | # Improved overload candidates 2 | 3 | Champion issue: 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | The overload resolution rules have been updated in nearly every C# language update to improve the experience for programmers, making ambiguous invocations select the "obvious" choice. This has to be done carefully to preserve backward compatibility, but since we are usually resolving what would otherwise be error cases, these enhancements usually work out nicely. 9 | 10 | 1. When a method group contains both instance and static members, we discard the instance members if invoked without an instance receiver or context, and discard the static members if invoked with an instance receiver. When there is no receiver, we include only static members in a static context, otherwise both static and instance members. When the receiver is ambiguously an instance or type due to a color-color situation, we include both. A static context, where an implicit this instance receiver cannot be used, includes the body of members where no this is defined, such as static members, as well as places where this cannot be used, such as field initializers and constructor-initializers. 11 | 2. When a method group contains some generic methods whose type arguments do not satisfy their constraints, these members are removed from the candidate set. 12 | 3. For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set. 13 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/indexing-movable-fixed-fields.md: -------------------------------------------------------------------------------- 1 | # Indexing `fixed` fields should not require pinning regardless of the movable/unmovable context. # 2 | 3 | Champion issue: 4 | 5 | The change has the size of a bug fix. It can be in 7.3 and does not conflict with whatever direction we take further. 6 | This change is only about allowing the following scenario to work even though `s` is moveable. It is already valid when `s` is not moveable. 7 | 8 | NOTE: in either case, it still requires `unsafe` context. It is possible to read uninitialized data or even out of range. That is not changing. 9 | 10 | ```csharp 11 | unsafe struct S 12 | { 13 | public fixed int myFixedField[10]; 14 | } 15 | 16 | class Program 17 | { 18 | static S s; 19 | 20 | unsafe static void Main() 21 | { 22 | int p = s.myFixedField[5]; // indexing fixed-size array fields would be ok 23 | } 24 | } 25 | ``` 26 | 27 | The main “challenge” that I see here is how to explain the relaxation in the spec. 28 | In particular, since the following would still need pinning. 29 | (because `s` is moveable and we explicitly use the field as a pointer) 30 | 31 | ```csharp 32 | unsafe struct S 33 | { 34 | public fixed int myFixedField[10]; 35 | } 36 | 37 | class Program 38 | { 39 | static S s; 40 | 41 | unsafe static void Main() 42 | { 43 | int* ptr = s.myFixedField; // taking a pointer explicitly still requires pinning. 44 | int p = ptr[5]; 45 | } 46 | } 47 | ``` 48 | 49 | One reason why we require pinning of the target when it is movable is the artifact of our code generation strategy, - we always convert to an unmanaged pointer and thus force the user to pin via `fixed` statement. However, conversion to unmanaged is unnecessary when doing indexing. The same unsafe pointer math is equally applicable when we have the receiver in the form of a managed pointer. If we do that, then the intermediate ref is managed (GC-tracked) and the pinning is unnecessary. 50 | 51 | The change https://github.com/dotnet/roslyn/pull/24966 is a prototype PR that relaxes this requirement. 52 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/ref-local-reassignment.md: -------------------------------------------------------------------------------- 1 | # Ref Local Reassignment 2 | 3 | Champion issue: 4 | 5 | In C# 7.3, we add support for rebinding the referent of a ref local variable or a ref parameter. 6 | 7 | We add the following to the set of `assignment_operator`s. 8 | 9 | ```antlr 10 | assignment_operator 11 | : '=' 'ref' 12 | ; 13 | ``` 14 | 15 | The `=ref` operator is called the ***ref assignment operator***. It is not a *compound assignment operator*. The left operand must be an expression that binds to a ref local variable, a ref parameter (other than `this`), or an out parameter. The right operand must be an expression that yields an lvalue designating a value of the same type as the left operand. 16 | 17 | The right operand must be definitely assigned at the point of the ref assignment. 18 | 19 | When the left operand binds to an `out` parameter, it is an error if that `out` parameter has not been definitely assigned at the beginning of the ref assignment operator. 20 | 21 | If the left operand is a writeable ref (i.e. it designates anything other than a `ref readonly` local or `in` parameter), then the right operand must be a writeable lvalue. 22 | 23 | The ref assignment operator yields an lvalue of the assigned type. It is writeable if the left operand is writeable (i.e. not `ref readonly` or `in`). 24 | 25 | The safety rules for this operator are: 26 | 27 | - For a ref reassignment `e1 = ref e2`, the *ref-safe-to-escape* of `e2` must be at least as wide a scope as the *ref-safe-to-escape* of `e1`. 28 | 29 | Where *ref-safe-to-escape* is defined in [Safety for ref-like types](../csharp-7.2/span-safety.md) 30 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/ref-loops.md: -------------------------------------------------------------------------------- 1 | ## Ref loops 2 | 3 | In C# 7.3, we added support for *ref for loops* and *ref foreach loops*. This is a placeholder for their specifications. 4 | -------------------------------------------------------------------------------- /proposals/csharp-7.3/stackalloc-array-initializers.md: -------------------------------------------------------------------------------- 1 | # Stackalloc array initializers 2 | 3 | Champion issue: 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | Allow array initializer syntax to be used with `stackalloc`. 9 | 10 | ## Motivation 11 | [motivation]: #motivation 12 | 13 | Ordinary arrays can have their elements initialized at creation time. It seems reasonable to allow that in `stackalloc` case. 14 | 15 | The question of why such syntax is not allowed with `stackalloc` arises fairly frequently. 16 | See, for example, [#1112](https://github.com/dotnet/csharplang/issues/1112) 17 | 18 | ## Detailed design 19 | 20 | Ordinary arrays can be created through the following syntax: 21 | 22 | ```csharp 23 | new int[3] 24 | new int[3] { 1, 2, 3 } 25 | new int[] { 1, 2, 3 } 26 | new[] { 1, 2, 3 } 27 | ``` 28 | 29 | We should allow stack allocated arrays be created through: 30 | 31 | ```csharp 32 | stackalloc int[3] // currently allowed 33 | stackalloc int[3] { 1, 2, 3 } 34 | stackalloc int[] { 1, 2, 3 } 35 | stackalloc[] { 1, 2, 3 } 36 | ``` 37 | 38 | The semantics of all cases is roughly the same as with arrays. 39 | For example: in the last case the element type is inferred from the initializer and must be an "unmanaged" type. 40 | 41 | NOTE: the feature is not dependent on the target being a `Span`. It is just as applicable in `T*` case, so it does not seem reasonable to predicate it on `Span` case. 42 | 43 | ## Translation 44 | 45 | The naive implementation could just initialize the array right after creation through a series of element-wise assignments. 46 | 47 | Similarly to the case with arrays, it might be possible and desirable to detect cases where all or most of the elements are blittable types and use more efficient techniques by copying over the pre-created state of all the constant elements. 48 | 49 | ## Drawbacks 50 | [drawbacks]: #drawbacks 51 | 52 | ## Alternatives 53 | [alternatives]: #alternatives 54 | 55 | This is a convenience feature. It is possible to just do nothing. 56 | 57 | ## Unresolved questions 58 | [unresolved]: #unresolved-questions 59 | 60 | ## Design meetings 61 | 62 | None yet. 63 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/proposals/csharp-8.0/README.md -------------------------------------------------------------------------------- /proposals/csharp-8.0/alternative-interpolated-verbatim.md: -------------------------------------------------------------------------------- 1 | ## Alternative interpolated verbatim strings 2 | 3 | Champion issue: 4 | 5 | In C# 8.0 we added a feature that permits an interpolated verbatim string to be introduced with the characters `@$"` or the characters `$@"`. This is a placeholder for its specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/async-using.md: -------------------------------------------------------------------------------- 1 | ## Async using declaration 2 | 3 | Champion issue: 4 | 5 | In C# 8.0 we added support for an *async using* statements. There are two forms. One has a block body that is the scope of the using declaratation. The other declares a local and is implicitly scoped to the end of the block. This is a placeholder for their specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/constraints-in-overrides.md: -------------------------------------------------------------------------------- 1 | ## Override with constraints 2 | 3 | In C# 8.0, we added a feature to permit the specification of certain type parameter constraints in an `override` method declaration. This is a placeholder for its specification. 4 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/constructed-unmanaged.md: -------------------------------------------------------------------------------- 1 | ## Unmanaged constructed types 2 | 3 | Champion issue: 4 | 5 | In C# 8.0, we extended the concept of an *unmanaged* type to include constructed (generic) types. This is a placeholder for its specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/nested-stackalloc.md: -------------------------------------------------------------------------------- 1 | # Permit `stackalloc` in nested contexts 2 | 3 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 4 | 5 | Champion issue: 6 | 7 | ## Stack allocation 8 | 9 | We modify the section *Stack allocation* ([§12.8.22 Stack allocation](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12822-stack-allocation)) of the C# language specification to relax the places when a `stackalloc` expression may appear. We delete 10 | 11 | ``` antlr 12 | local_variable_initializer_unsafe 13 | : stackalloc_initializer 14 | ; 15 | 16 | stackalloc_initializer 17 | : 'stackalloc' unmanaged_type '[' expression ']' 18 | ; 19 | ``` 20 | 21 | and replace them with 22 | 23 | ``` antlr 24 | primary_no_array_creation_expression 25 | : stackalloc_initializer 26 | ; 27 | 28 | stackalloc_initializer 29 | : 'stackalloc' unmanaged_type '[' expression? ']' array_initializer? 30 | | 'stackalloc' '[' expression? ']' array_initializer 31 | ; 32 | ``` 33 | 34 | Note that the addition of an *array_initializer* to *stackalloc_initializer* (and making the index expression optional) was an extension in C# 7.3 and is not described here. 35 | 36 | The *element type* of the `stackalloc` expression is the *unmanaged_type* named in the stackalloc expression, if any, or the common type among the elements of the *array_initializer* otherwise. 37 | 38 | The type of the *stackalloc_initializer* with *element type* `K` depends on its syntactic context: 39 | - If the *stackalloc_initializer* appears directly as the *local_variable_initializer* of a *local_variable_declaration* statement or a *for_initializer*, then its type is `K*`. 40 | - Otherwise its type is `System.Span`. 41 | 42 | ## Stackalloc Conversion 43 | 44 | The *stackalloc conversion* is a new built-in implicit conversion from expression. When the type of a *stackalloc_initializer* is `K*`, there is an implicit *stackalloc conversion* from the *stackalloc_initializer* to the type `System.Span`. 45 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/notnull-constraint.md: -------------------------------------------------------------------------------- 1 | ## Notnull constraint 2 | 3 | Champion issue: 4 | 5 | In C# 8.0, we added a language feature that permits the specification of a new type parameter constraint `notnull`. This is a placeholder for its specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/obsolete-accessor.md: -------------------------------------------------------------------------------- 1 | ## Obsolete on property accessor 2 | 3 | Champion issue: 4 | 5 | In C# 8.0, we added support for declaring a property accessor `[Obsolete]`. This is a placeholder for the specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/shadowing-in-nested-functions.md: -------------------------------------------------------------------------------- 1 | # Name shadowing in nested functions 2 | 3 | Champion issue: 4 | 5 | ## Summary 6 | 7 | Permit variable names in lambdas and local functions to reuse (and shadow) names from the enclosing method or function. 8 | 9 | ## Detailed design 10 | 11 | With `-langversion:8`, names of locals, local functions, parameters, type parameters, and range variables within a lambda or local function can reuse names of locals, local functions, parameters, type parameters, and range variables from an enclosing method or function. The name in the nested function hides the symbol of the same name from the enclosing function within the nested function. 12 | 13 | Shadowing is supported for `static` and non-`static` local functions and lambdas. 14 | 15 | There is no change in behavior using `-langversion:7.3` or earlier: names in nested functions that shadow names from the enclosing method or function are reported as errors in those cases. 16 | 17 | Any shadowing previously permitted is still supported with `-langversion:8`. For instance: variable names may shadow type and member names; and variable names may shadow enclosing method or local function names. 18 | 19 | Shadowing a name declared in an enclosing scope in the same lambda or local function is still reported as an error. 20 | 21 | A warning is reported for a type parameter in a local function that shadows a type parameter in the enclosing type, method, or function. 22 | 23 | ## Design meetings 24 | 25 | - https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-09-10.md#static-local-functions 26 | - https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-01-16.md#shadowing-in-nested-functions 27 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/static-local-functions.md: -------------------------------------------------------------------------------- 1 | # Static local functions 2 | 3 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 4 | 5 | Champion issue: 6 | 7 | ## Summary 8 | 9 | Support local functions that disallow capturing state from the enclosing scope. 10 | 11 | ## Motivation 12 | 13 | Avoid unintentionally capturing state from the enclosing context. 14 | Allow local functions to be used in scenarios where a `static` method is required. 15 | 16 | ## Detailed design 17 | 18 | A local function declared `static` cannot capture state from the enclosing scope. 19 | As a result, locals, parameters, and `this` from the enclosing scope are not available within a `static` local function. 20 | 21 | A `static` local function cannot reference instance members from an implicit or explicit `this` or `base` reference. 22 | 23 | A `static` local function may reference `static` members from the enclosing scope. 24 | 25 | A `static` local function may reference `constant` definitions from the enclosing scope. 26 | 27 | `nameof()` in a `static` local function may reference locals, parameters, or `this` or `base` from the enclosing scope. 28 | 29 | Accessibility rules for `private` members in the enclosing scope are the same for `static` and non-`static` local functions. 30 | 31 | A `static` local function definition is emitted as a `static` method in metadata, even if only used in a delegate. 32 | 33 | A non-`static` local function or lambda can capture state from an enclosing `static` local function but cannot capture state outside the enclosing `static` local function. 34 | 35 | A `static` local function cannot be invoked in an expression tree. 36 | 37 | A call to a local function is emitted as `call` rather than `callvirt`, regardless of whether the local function is `static`. 38 | 39 | Overload resolution of a call within a local function not affected by whether the local function is `static`. 40 | 41 | Removing the `static` modifier from a local function in a valid program does not change the meaning of the program. 42 | 43 | ## Design meetings 44 | 45 | https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-09-10.md#static-local-functions 46 | -------------------------------------------------------------------------------- /proposals/csharp-8.0/unconstrained-null-coalescing.md: -------------------------------------------------------------------------------- 1 | ## Unconstrained type parameter in null coalescing operator 2 | 3 | Champion issue: 4 | 5 | In C# 8.0 we introduced a feature that permits a null coalescing operator to have a left operand that is not known to be either a reference or value type (i.e. an unconstrained type parameter). This is a placeholder for its specification. 6 | -------------------------------------------------------------------------------- /proposals/csharp-9.0/lambda-discard-parameters.md: -------------------------------------------------------------------------------- 1 | # Lambda discard parameters 2 | 3 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 4 | 5 | Champion issue: 6 | 7 | ## Summary 8 | 9 | Allow discards (`_`) to be used as parameters of lambdas and anonymous methods. 10 | For example: 11 | - lambdas: `(_, _) => 0`, `(int _, int _) => 0` 12 | - anonymous methods: `delegate(int _, int _) { return 0; }` 13 | 14 | ## Motivation 15 | 16 | Unused parameters do not need to be named. The intent of discards is clear, i.e. they are unused/discarded. 17 | 18 | ## Detailed design 19 | 20 | Method parameters - [§15.6.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1562-method-parameters) 21 | In the parameter list of a lambda or anonymous method with more than one parameter named `_`, such parameters are discard parameters. 22 | Note: if a single parameter is named `_` then it is a regular parameter for backwards compatibility reasons. 23 | 24 | Discard parameters do not introduce any names to any scopes. 25 | Note this implies they do not cause any `_` (underscore) names to be hidden. 26 | 27 | Simple names ([§12.8.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1284-simple-names)) 28 | If `K` is zero and the *simple_name* appears within a *block* and if the *block*'s (or an enclosing *block*'s) local variable declaration space (Declarations - [§7.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#73-declarations)) contains a local variable, parameter (with the exception of discard parameters) or constant with name `I`, then the *simple_name* refers to that local variable, parameter or constant and is classified as a variable or value. 29 | 30 | Scopes - [§7.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#77-scopes) 31 | With the exception of discard parameters, the scope of a parameter declared in a *lambda_expression* ([§12.19](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1219-anonymous-function-expressions)) is the *anonymous_function_body* of that *lambda_expression* 32 | With the exception of discard parameters, the scope of a parameter declared in an *anonymous_method_expression* ([§12.19](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1219-anonymous-function-expressions)) is the *block* of that *anonymous_method_expression*. 33 | 34 | ## Related spec sections 35 | - Corresponding parameters - [§12.6.2.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12622-corresponding-parameters) 36 | -------------------------------------------------------------------------------- /proposals/csharp-9.0/local-function-attributes.md: -------------------------------------------------------------------------------- 1 | # Attributes on local functions 2 | 3 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 4 | 5 | Champion issue: 6 | 7 | ## Attributes 8 | 9 | Local function declarations are now permitted to have attributes ([§22](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/attributes.md#22-attributes)). Parameters and type parameters on local functions are also allowed to have attributes. 10 | 11 | Attributes with a specified meaning when applied to a method, its parameters, or its type parameters will have the same meaning when applied to a local function, its parameters, or its type parameters, respectively. 12 | 13 | A local function can be made conditional in the same sense as a conditional method ([§22.5.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/attributes.md#2253-the-conditional-attribute)) by decorating it with a `[ConditionalAttribute]`. A conditional local function must also be `static`. All restrictions on conditional methods also apply to conditional local functions, including that the return type must be `void`. 14 | 15 | ## Extern 16 | 17 | The `extern` modifier is now permitted on local functions. This makes the local function external in the same sense as an external method ([§15.6.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1468-external-methods)). 18 | 19 | Similarly to an external method, the *local-function-body* of an external local function must be a semicolon. A semicolon *local-function-body* is only permitted on an external local function. 20 | 21 | An external local function must also be `static`. 22 | 23 | ## Syntax 24 | 25 | The [§13.6.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1364-local-function-declarations), or [local functions grammar](../csharp-7.0/local-functions.md#syntax-grammar) is modified as follows: 26 | 27 | ``` 28 | local-function-header 29 | : attributes? local-function-modifiers? return-type identifier type-parameter-list? 30 | ( formal-parameter-list? ) type-parameter-constraints-clauses 31 | ; 32 | 33 | local-function-modifiers 34 | : (async | unsafe | static | extern)* 35 | ; 36 | 37 | local-function-body 38 | : block 39 | | arrow-expression-body 40 | | ';' 41 | ; 42 | ``` 43 | -------------------------------------------------------------------------------- /proposals/csharp-9.0/static-anonymous-functions.md: -------------------------------------------------------------------------------- 1 | # Static anonymous functions 2 | 3 | [!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)] 4 | 5 | Champion issue: 6 | 7 | ## Summary 8 | 9 | Allow a 'static' modifier on lambdas and anonymous methods, which disallows capture of locals or instance state from containing scopes. 10 | 11 | ## Motivation 12 | 13 | Avoid unintentionally capturing state from the enclosing context, which can result in unexpected retention of captured objects or unexpected additional allocations. 14 | 15 | ## Detailed design 16 | 17 | A lambda or anonymous method may have a `static` modifier. The `static` modifier indicates that the lambda or anonymous method is a *static anonymous function*. 18 | 19 | A *static anonymous function* cannot capture state from the enclosing scope. 20 | As a result, locals, parameters, and `this` from the enclosing scope are not available within a *static anonymous function*. 21 | 22 | A *static anonymous function* cannot reference instance members from an implicit or explicit `this` or `base` reference. 23 | 24 | A *static anonymous function* may reference `static` members from the enclosing scope. 25 | 26 | A *static anonymous function* may reference `constant` definitions from the enclosing scope. 27 | 28 | `nameof()` in a *static anonymous function* may reference locals, parameters, or `this` or `base` from the enclosing scope. 29 | 30 | Accessibility rules for `private` members in the enclosing scope are the same for `static` and non-`static` anonymous functions. 31 | 32 | No guarantee is made as to whether a *static anonymous function* definition is emitted as a `static` method in metadata. This is left up to the compiler implementation to optimize. 33 | 34 | A non-`static` local function or anonymous function can capture state from an enclosing *static anonymous function* but cannot capture state outside the enclosing *static anonymous function*. 35 | 36 | Removing the `static` modifier from an anonymous function in a valid program does not change the meaning of the program. 37 | -------------------------------------------------------------------------------- /proposals/inactive/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/proposals/inactive/README.md -------------------------------------------------------------------------------- /proposals/null-conditional-await.md: -------------------------------------------------------------------------------- 1 | # null-conditional await 2 | 3 | Champion issue: 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | Support an expression of the form `await? e`, which awaits `e` if it is non-null, otherwise it results in `null`. 9 | 10 | ## Motivation 11 | [motivation]: #motivation 12 | 13 | This is a common coding pattern, and this feature would have nice synergy with the existing null-propagating and null-coalescing operators. 14 | 15 | ## Detailed design 16 | [design]: #detailed-design 17 | 18 | We add a new form of the *await_expression*: 19 | 20 | ```antlr 21 | await_expression 22 | : 'await' '?' unary_expression 23 | ; 24 | ``` 25 | 26 | The null-conditional `await` operator awaits its operand only if that operand is non-null. Otherwise the result of applying the operator is null. 27 | 28 | The type of the result is computed using the rules for the null-conditional operator [§11.7.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1177-null-conditional-member-access). 29 | 30 | > **NOTE:** 31 | > If `e` is of type `Task`, then `await? e;` would do nothing if `e` is `null`, and await `e` if it is not `null`. 32 | > 33 | > If `e` is of type `Task` where `K` is a value type, then `await? e` would yield a value of type `K?`. 34 | 35 | ## Drawbacks 36 | [drawbacks]: #drawbacks 37 | 38 | As with any language feature, we must question whether the additional complexity to the language is repaid in the additional clarity offered to the body of C# programs that would benefit from the feature. 39 | 40 | ## Alternatives 41 | [alternatives]: #alternatives 42 | 43 | Although it requires some boilerplate code, uses of this operator can often be replaced by an expression something like `(e == null) ? null : await e` or a statement like `if (e != null) await e`. 44 | 45 | ## Unresolved questions 46 | [unresolved]: #unresolved-questions 47 | 48 | - [ ] Requires LDM review 49 | 50 | ## Design meetings 51 | 52 | None. 53 | -------------------------------------------------------------------------------- /proposals/optional-and-named-parameters-in-expression-trees.md: -------------------------------------------------------------------------------- 1 | # Support optional and named arguments in Expression trees 2 | 3 | Champion issue: https://github.com/dotnet/csharplang/issues/9246 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | Support optional and named arguments in method calls in `Expression` trees 9 | 10 | ## Motivation 11 | [motivation]: #motivation 12 | 13 | Errors are reported for calls in `Expression` trees when the call is missing an argument for an optional parameter, or when arguments are named. 14 | 15 | This results in unnecessary code and differences for expressions within `Expression` trees. And lack of support for optional arguments can lead to breaking changes when a new overload with an optional parameter is applicable at an existing call site. 16 | 17 | The compiler restrictions should be removed if not needed. 18 | 19 | For example, compiling the following with the .NET 10 preview SDK results in errors currently. 20 | 21 | ```csharp 22 | namespace System 23 | { 24 | public static class MemoryExtensions 25 | { 26 | public static bool Contains(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null); 27 | } 28 | } 29 | 30 | Expression> e; 31 | 32 | e = (a, i) => a.Contains(i); // error CS0854: expression tree may not contain a call that uses optional arguments 33 | e = (a, i) => a.Contains(i, comparer: null); // error CS0853: expression tree may not contain a named argument specification 34 | ``` 35 | 36 | ## Detailed design 37 | [design]: #design 38 | 39 | Remove the error reporting for these cases in `Expression` trees, and allow the existing method call rewriting to handle optional and named arguments. 40 | 41 | ## Drawbacks 42 | [drawbacks]: #drawbacks 43 | 44 | ## Alternatives 45 | [alternatives]: #alternatives 46 | 47 | ## Unresolved questions 48 | [unresolved]: #unresolved-questions 49 | 50 | It's unclear why the restrictions were added originally. An initial investigation hasn't revealed an issue supporting these cases. 51 | 52 | ## Design meetings 53 | [meetings]: #meetings 54 | 55 | *Based on a suggestion from @roji to support optional parameters.* 56 | -------------------------------------------------------------------------------- /proposals/proposal-template.md: -------------------------------------------------------------------------------- 1 | # FEATURE_NAME 2 | 3 | Champion issue: 4 | 5 | ## Summary 6 | [summary]: #summary 7 | 8 | One paragraph explanation of the feature. 9 | 10 | ## Motivation 11 | [motivation]: #motivation 12 | 13 | Why are we doing this? What use cases does it support? What is the expected outcome? 14 | 15 | ## Detailed design 16 | [design]: #detailed-design 17 | 18 | This is the bulk of the proposal. Explain the design in enough detail for somebody familiar with the language to understand, and for somebody familiar with the compiler to implement, and include examples of how the feature is used. This section can start out light before the prototyping phase but should get into specifics and corner-cases as the feature is iteratively designed and implemented. 19 | 20 | ## Drawbacks 21 | [drawbacks]: #drawbacks 22 | 23 | Why should we *not* do this? 24 | 25 | ## Alternatives 26 | [alternatives]: #alternatives 27 | 28 | What other designs have been considered? What is the impact of not doing this? 29 | 30 | ## Open questions 31 | [open]: #open-questions 32 | 33 | What parts of the design are still undecided? 34 | 35 | -------------------------------------------------------------------------------- /proposals/rejected/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/csharplang/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/proposals/rejected/README.md -------------------------------------------------------------------------------- /proposals/speclet-disclaimer.md: -------------------------------------------------------------------------------- 1 | > [!NOTE] 2 | > This article is a feature specification. The specification serves as the design document for the feature. It includes proposed specification changes, along with information needed during the design and development of the feature. These articles are published until the proposed spec changes are finalized and incorporated in the current ECMA specification. 3 | > 4 | > There may be some discrepancies between the feature specification and the completed implementation. Those differences are captured in the pertinent [language design meeting (LDM) notes](https://github.com/dotnet/csharplang/tree/main/meetings). 5 | > 6 | > You can learn more about the process for adopting feature speclets into the C# language standard in the article on the [specifications](https://learn.microsoft.com/dotnet/csharp/specification/feature-spec-overview). 7 | -------------------------------------------------------------------------------- /spec/LICENSE.md: -------------------------------------------------------------------------------- 1 | THE FOLLOWING NOTICE GOVERNS THE C# SPEC 2 | ===== 3 | 4 | (c) Copyright 1999-2017 Microsoft Corporation. All rights reserved. 5 | Microsoft, Windows, Visual Basic, Visual C#, and Visual C++ are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries/regions. 6 | Other product and company names mentioned herein may be the trademarks of their respective owners. 7 | -------------------------------------------------------------------------------- /spec/arrays.md: -------------------------------------------------------------------------------- 1 | # Arrays 2 | 3 | This content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository. 4 | The list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged. 5 | 6 | > To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository. 7 | 8 | - [Arrays](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#16-arrays) 9 | - [Array types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#162-array-types) 10 | - [The System.Array type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#1622-the-systemarray-type) 11 | - [Arrays and the generic IList interface](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#1623-arrays-and-the-generic-collection-interfaces) 12 | - [Array creation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#163-array-creation) 13 | - [Array element access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#164-array-element-access) 14 | - [Array members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#165-array-members) 15 | - [Array covariance](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#166-array-covariance) 16 | - [Array initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#167-array-initializers) 17 | -------------------------------------------------------------------------------- /spec/delegates.md: -------------------------------------------------------------------------------- 1 | # Delegates 2 | 3 | This content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository. 4 | The list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged. 5 | 6 | > To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository. 7 | 8 | - [Delegates](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#19-delegates) 9 | - [Delegate declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#192-delegate-declarations) 10 | - [Delegate compatibility](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#194-delegate-compatibility) 11 | - [Delegate instantiation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#195-delegate-instantiation) 12 | - [Delegate invocation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#196-delegate-invocation) 13 | -------------------------------------------------------------------------------- /spec/enums.md: -------------------------------------------------------------------------------- 1 | # Enums 2 | 3 | This content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository. 4 | The list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged. 5 | 6 | > To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository. 7 | 8 | - [Enums](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#18-enums) 9 | - [Enum declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#182-enum-declarations) 10 | - [Enum modifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#183-enum-modifiers) 11 | - [Enum members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#184-enum-members) 12 | - [The System.Enum type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#185-the-systemenum-type) 13 | - [Enum values and operations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#186-enum-values-and-operations) 14 | -------------------------------------------------------------------------------- /spec/exceptions.md: -------------------------------------------------------------------------------- 1 | # Exceptions 2 | 3 | This content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository. 4 | The list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged. 5 | 6 | > To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository. 7 | 8 | - [Exceptions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#20-exceptions) 9 | - [Causes of exceptions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#202-causes-of-exceptions) 10 | - [The System.Exception class](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#203-the-systemexception-class) 11 | - [How exceptions are handled](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#204-how-exceptions-are-handled) 12 | - [Common Exception Classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#205-common-exception-classes) 13 | -------------------------------------------------------------------------------- /spec/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository. This section has been removed from the standard. The [standard/README.md](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/README.md) has a detailed table of contents for the standard. 4 | 5 | > To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository. 6 | -------------------------------------------------------------------------------- /spec/namespaces.md: -------------------------------------------------------------------------------- 1 | # Namespaces 2 | 3 | This content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository. 4 | The list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged. 5 | 6 | > To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository. 7 | 8 | - [Namespaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#13-namespaces) 9 | - [Compilation units](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#132-compilation-units) 10 | - [Namespace declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#133-namespace-declarations) 11 | - [Extern aliases](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#134-extern-alias-directives) 12 | - [Using directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#135-using-directives) 13 | - [Using alias directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1352-using-alias-directives) 14 | - [Using namespace directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1353-using-namespace-directives) 15 | - [Using static directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1354-using-static-directives) 16 | - [Namespace members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#136-namespace-member-declarations) 17 | - [Type declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#137-type-declarations) 18 | - [Namespace alias qualifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#138-qualified-alias-member) 19 | - [Uniqueness of aliases](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1382-uniqueness-of-aliases) 20 | --------------------------------------------------------------------------------